- initial way labeling

- add no-projection option for mapdata
- use depth buffer for line clipping to tile - no more scissor, yay!
- extract line and poly render function from maprenderer
- use one vbo for both polys and lines
- use linear interpolator for fling-scroller
- add 'exclusive' negative matcher to rendertheme
- add some more options to rendertheme, kind of inheritance at least for
  lines, see theme
- add caching for node tags -> renderinstructions
- ...
This commit is contained in:
Hannes Janetzek 2012-08-28 09:25:06 +02:00
parent 1cf0c02dd2
commit 2fccf0f214
46 changed files with 3591 additions and 2815 deletions

View File

@ -16,6 +16,7 @@ package org.mapsforge.android;
import org.mapsforge.android.mapgenerator.IMapGenerator; import org.mapsforge.android.mapgenerator.IMapGenerator;
import org.mapsforge.android.mapgenerator.MapGeneratorJob; import org.mapsforge.android.mapgenerator.MapGeneratorJob;
import org.mapsforge.android.rendertheme.RenderTheme;
import android.opengl.GLSurfaceView; import android.opengl.GLSurfaceView;
@ -46,4 +47,6 @@ public interface IMapRenderer extends GLSurfaceView.Renderer {
public void redrawTiles(boolean clear); public void redrawTiles(boolean clear);
public IMapGenerator createMapGenerator(); public IMapGenerator createMapGenerator();
public void setRenderTheme(RenderTheme t);
} }

View File

@ -496,6 +496,7 @@ public class MapView extends GLSurfaceView {
* *
* @param internalRenderTheme * @param internalRenderTheme
* the internal rendering theme. * the internal rendering theme.
* @return ...
* @throws IllegalArgumentException * @throws IllegalArgumentException
* if the supplied internalRenderTheme is null. * if the supplied internalRenderTheme is null.
*/ */
@ -538,6 +539,7 @@ public class MapView extends GLSurfaceView {
try { try {
inputStream = theme.getRenderThemeAsStream(); inputStream = theme.getRenderThemeAsStream();
RenderTheme t = RenderThemeHandler.getRenderTheme(inputStream); RenderTheme t = RenderThemeHandler.getRenderTheme(inputStream);
mMapRenderer.setRenderTheme(t);
mMapWorkers[0].getMapGenerator().setRenderTheme(t); mMapWorkers[0].getMapGenerator().setRenderTheme(t);
return true; return true;
} catch (ParserConfigurationException e) { } catch (ParserConfigurationException e) {

View File

@ -14,21 +14,23 @@
*/ */
package org.mapsforge.android.glrenderer; package org.mapsforge.android.glrenderer;
import java.util.ArrayList;
import org.mapsforge.android.mapgenerator.MapTile; import org.mapsforge.android.mapgenerator.MapTile;
import org.mapsforge.core.Tile; import org.mapsforge.core.Tile;
class GLMapTile extends MapTile { class GLMapTile extends MapTile {
long lastDraw = 0;
VertexBufferObject vbo;
// polygonOffset is always 8
int lineOffset;
VertexBufferObject lineVBO;
VertexBufferObject polygonVBO;
TextTexture texture; TextTexture texture;
LineLayer lineLayers; LineLayer lineLayers;
PolygonLayer polygonLayers; PolygonLayer polygonLayers;
ArrayList<TextItem> labels; TextItem labels;
boolean newData; boolean newData;
boolean loading; boolean loading;
@ -37,9 +39,6 @@ class GLMapTile extends MapTile {
final long x; final long x;
final long y; final long y;
// scissor coordinates
int sx, sy, sw, sh;
final GLMapTile[] child = { null, null, null, null }; final GLMapTile[] child = { null, null, null, null };
GLMapTile parent; GLMapTile parent;

View File

@ -15,38 +15,35 @@
package org.mapsforge.android.glrenderer; package org.mapsforge.android.glrenderer;
import org.mapsforge.android.rendertheme.renderinstruction.Line; import org.mapsforge.android.rendertheme.renderinstruction.Line;
import org.mapsforge.core.Tile;
import android.graphics.Paint.Cap;
import android.util.FloatMath; import android.util.FloatMath;
class LineLayer { class LineLayer {
private static final float SCALE_FACTOR = 16; private static final float S = MapRenderer.COORD_MULTIPLIER;
private static final float S1000 = 1000;
Line line;
LineLayer next; LineLayer next;
LineLayer outlines; LineLayer outlines;
Line line;
float width; float width;
boolean isOutline; boolean isOutline;
int layer;
ShortItem pool; ShortItem pool;
protected ShortItem curItem; protected ShortItem curItem;
int verticesCnt; int verticesCnt;
int offset; int offset;
short[] mVertex;
final int layer; LineLayer(int layer, Line line, float width, boolean outline) {
LineLayer(int layer, Line line, boolean outline) {
this.layer = layer; this.layer = layer;
this.width = width;
this.line = line; this.line = line;
this.isOutline = outline; this.isOutline = outline;
if (!outline) {
curItem = ShortPool.get();
pool = curItem;
}
} }
void addOutline(LineLayer link) { void addOutline(LineLayer link) {
@ -58,45 +55,82 @@ class LineLayer {
outlines = link; outlines = link;
} }
short[] getNextItem() { private static ShortItem addTwoVertex(short[] vertex, ShortItem item) {
curItem.used = ShortItem.SIZE; ShortItem it = item;
curItem.next = ShortPool.get(); if (it.used + 6 >= ShortItem.SIZE) {
curItem = curItem.next;
return curItem.vertices; if (it.used == ShortItem.SIZE) {
it.next = ShortPool.get();
it = it.next;
} else {
System.arraycopy(vertex, 0, it.vertices, it.used, 6);
it.used += 6;
it.next = ShortPool.get();
it = it.next;
System.arraycopy(vertex, 6, it.vertices, it.used, 6);
it.used += 6;
return it;
}
}
System.arraycopy(vertex, 0, it.vertices, it.used, 12);
it.used += 12;
return it;
}
private static ShortItem addVertex(short[] vertex, ShortItem item) {
ShortItem it = item;
if (it.used == ShortItem.SIZE) {
it.next = ShortPool.get();
it = it.next;
}
System.arraycopy(vertex, 0, it.vertices, it.used, 6);
it.used += 6;
return it;
} }
/* /*
* line extrusion is based on code from GLMap (https://github.com/olofsj/GLMap/) by olofsj * line extrusion is based on code from GLMap (https://github.com/olofsj/GLMap/) by olofsj -- need some way to know
* how the road connects to set the ending angles
*/ */
void addLine(float[] pointArray, int pos, int length, float w, boolean capRound) { void addLine(float[] pointArray, int pos, int length) {
float x, y, nextX, nextY, prevX, prevY, ux, uy, vx, vy, wx, wy; float x, y, nextX, nextY, prevX, prevY, ux, uy, vx, vy, wx, wy;
float a; float a;
int pointPos = pos; int pointPos = pos;
boolean rounded = capRound; boolean rounded = false;
width = w;// * SCALE_FACTOR; boolean squared = false;
if (w < 0.5)
rounded = false; if (line.cap == Cap.ROUND)
rounded = true;
else if (line.cap == Cap.SQUARE)
squared = true;
if (pool == null) {
curItem = ShortPool.get();
pool = curItem;
mVertex = new short[12];
}
// amount of vertices used // amount of vertices used
verticesCnt += length + (rounded ? 6 : 2); verticesCnt += length + (rounded ? 6 : 2);
int MAX = PoolItem.SIZE; ShortItem si = curItem;
short[] curVertices = curItem.vertices; x = pointArray[pointPos++];
int vertexPos = curItem.used; y = pointArray[pointPos++];
if (vertexPos == MAX) { nextX = pointArray[pointPos++];
curVertices = getNextItem(); nextY = pointArray[pointPos++];
vertexPos = 0;
}
x = pointArray[pointPos++];// * SCALE_FACTOR;
y = pointArray[pointPos++];// * SCALE_FACTOR;
nextX = pointArray[pointPos++];// * SCALE_FACTOR;
nextY = pointArray[pointPos++];// * SCALE_FACTOR;
// Calculate triangle corners for the given width // Calculate triangle corners for the given width
vx = nextX - x; vx = nextX - x;
@ -110,109 +144,83 @@ class LineLayer {
ux = -vy; ux = -vy;
uy = vx; uy = vx;
float uxw = ux * w; float uxw = ux;
float uyw = uy * w; float uyw = uy;
float vxw = vx * w; float vxw = vx;
float vyw = vy * w; float vyw = vy;
int tsize = Tile.TILE_SIZE;
// boolean outside = (x <= 0 || x >= Tile.TILE_SIZE || y <= 0 || y >= Tile.TILE_SIZE) short v[] = mVertex;
// && (x - vxw <= 0 || x - vxw >= Tile.TILE_SIZE || y - vyw <= 0 || y - vyw >= Tile.TILE_SIZE);
v[0] = (short) (x * S);
v[1] = (short) (y * S);
boolean outside = (x <= 0 || x >= tsize || y <= 0 || y >= tsize)
&& (x - vxw <= 0 || x - vxw >= tsize || y - vyw <= 0 || y - vyw >= tsize);
boolean outside = false;
if (rounded && !outside) { if (rounded && !outside) {
v[2] = (short) ((uxw - vxw) * S1000);
v[3] = (short) ((uyw - vyw) * S1000);
v[4] = -1;
v[5] = 1;
si = addVertex(v, si);
si = addVertex(v, si);
// Add the first point twice to be able to draw with GL_TRIANGLE_STRIP v[2] = (short) (-(uxw + vxw) * S1000);
v[3] = (short) (-(uyw + vyw) * S1000);
curVertices[vertexPos++] = (short) ((x + uxw - vxw) * SCALE_FACTOR); v[4] = 1;
curVertices[vertexPos++] = (short) ((y + uyw - vyw) * SCALE_FACTOR); v[5] = 1;
curVertices[vertexPos++] = -1; si = addVertex(v, si);
curVertices[vertexPos++] = 1;
if (vertexPos == MAX) {
curVertices = getNextItem();
vertexPos = 0;
}
curVertices[vertexPos++] = (short) ((x + uxw - vxw) * SCALE_FACTOR);
curVertices[vertexPos++] = (short) ((y + uyw - vyw) * SCALE_FACTOR);
curVertices[vertexPos++] = -1;
curVertices[vertexPos++] = 1;
if (vertexPos == MAX) {
curVertices = getNextItem();
vertexPos = 0;
}
curVertices[vertexPos++] = (short) ((x - uxw - vxw) * SCALE_FACTOR);
curVertices[vertexPos++] = (short) ((y - uyw - vyw) * SCALE_FACTOR);
curVertices[vertexPos++] = 1;
curVertices[vertexPos++] = 1;
if (vertexPos == MAX) {
curVertices = getNextItem();
vertexPos = 0;
}
// Start of line // Start of line
curVertices[vertexPos++] = (short) ((x + uxw) * SCALE_FACTOR); v[2] = (short) ((uxw) * S1000);
curVertices[vertexPos++] = (short) ((y + uyw) * SCALE_FACTOR); v[3] = (short) ((uyw) * S1000);
curVertices[vertexPos++] = -1; v[4] = -1;
curVertices[vertexPos++] = 0; v[5] = 0;
si = addVertex(v, si);
if (vertexPos == MAX) { v[2] = (short) ((-uxw) * S1000);
curVertices = getNextItem(); v[3] = (short) ((-uyw) * S1000);
vertexPos = 0; v[4] = 1;
} v[5] = 0;
si = addVertex(v, si);
curVertices[vertexPos++] = (short) ((x - uxw) * SCALE_FACTOR);
curVertices[vertexPos++] = (short) ((y - uyw) * SCALE_FACTOR);
curVertices[vertexPos++] = 1;
curVertices[vertexPos++] = 0;
} else { } else {
// outside means line is probably clipped // outside means line is probably clipped
// TODO should align ending with tile boundary // TODO should align ending with tile boundary
// for now, just extend the line a little // for now, just extend the line a little
if (!outside) {
if (squared) {
vxw = 0;
vyw = 0;
} else if (!outside) {
vxw *= 0.5; vxw *= 0.5;
vyw *= 0.5; vyw *= 0.5;
} }
if (rounded) {
if (rounded)
verticesCnt -= 2; verticesCnt -= 2;
}
// Add the first point twice to be able to draw with GL_TRIANGLE_STRIP // Add the first point twice to be able to draw with GL_TRIANGLE_STRIP
curVertices[vertexPos++] = (short) ((x + uxw - vxw) * SCALE_FACTOR); v[2] = (short) ((uxw - vxw) * S1000);
curVertices[vertexPos++] = (short) ((y + uyw - vyw) * SCALE_FACTOR); v[3] = (short) ((uyw - vyw) * S1000);
curVertices[vertexPos++] = -1; v[4] = -1;
curVertices[vertexPos++] = 0; v[5] = 0;
si = addVertex(v, si);
si = addVertex(v, si);
if (vertexPos == MAX) { v[2] = (short) (-(uxw + vxw) * S1000);
curVertices = getNextItem(); v[3] = (short) (-(uyw + vyw) * S1000);
vertexPos = 0; v[4] = 1;
} v[5] = 0;
si = addVertex(v, si);
curVertices[vertexPos++] = (short) ((x + uxw - vxw) * SCALE_FACTOR);
curVertices[vertexPos++] = (short) ((y + uyw - vyw) * SCALE_FACTOR);
curVertices[vertexPos++] = -1;
curVertices[vertexPos++] = 0;
if (vertexPos == MAX) {
curVertices = getNextItem();
vertexPos = 0;
}
curVertices[vertexPos++] = (short) ((x - uxw - vxw) * SCALE_FACTOR);
curVertices[vertexPos++] = (short) ((y - uyw - vyw) * SCALE_FACTOR);
curVertices[vertexPos++] = 1;
curVertices[vertexPos++] = 0;
} }
prevX = x; prevX = x;
prevY = y; prevY = y;
x = nextX; x = nextX;
y = nextY; y = nextY;
// boolean flipped = false;
for (; pointPos < pos + length;) { for (; pointPos < pos + length;) {
nextX = pointArray[pointPos++]; nextX = pointArray[pointPos++];
@ -235,58 +243,40 @@ class LineLayer {
// Sum of these two vectors points // Sum of these two vectors points
ux = vx + wx; ux = vx + wx;
uy = vy + wy; uy = vy + wy;
a = -wy * ux + wx * uy; a = -wy * ux + wx * uy;
if ((a < 0.1 && a > -0.1)) { // boolean split = false;
// Almost straight, use normal vector if (a < 0.1f && a > -0.1f) {
// Almost straight or miter goes to infinity, use normal vector
ux = -wy; ux = -wy;
uy = wx; uy = wx;
} else { } else {
ux = (ux / a); ux = (ux / a);
uy = (uy / a); uy = (uy / a);
if (ux > 2 || uy > 2 || ux < -2 || uy < -2) { if (ux > 2.0f || ux < -2.0f || uy > 2.0f || uy < -2.0f) {
ux = -wy; ux = -wy;
uy = wx; uy = wx;
// ux = vx + wx;
// uy = vy + wy;
// // Normalize u, and project normal vector onto this
// double c = Math.sqrt(ux * ux + uy * uy);
// if (a < 0) {
// ux = (float) -(ux / c);
// uy = (float) -(uy / c);
// }
// else {
// ux = (float) (ux / c);
// uy = (float) (uy / c);
// }
// flipped = flipped ? false : true;
} }
} }
uxw = ux * w; uxw = ux * S1000;
uyw = uy * w; uyw = uy * S1000;
if (vertexPos == MAX) { v[6] = v[0] = (short) (x * S);
curVertices = getNextItem(); v[7] = v[1] = (short) (y * S);
vertexPos = 0;
}
curVertices[vertexPos++] = (short) ((x + uxw) * SCALE_FACTOR); v[2] = (short) uxw;
curVertices[vertexPos++] = (short) ((y + uyw) * SCALE_FACTOR); v[3] = (short) uyw;
curVertices[vertexPos++] = -1; v[4] = -1;
curVertices[vertexPos++] = 0; v[5] = 0;
if (vertexPos == MAX) { v[8] = (short) -uxw;
curVertices = getNextItem(); v[9] = (short) -uyw;
vertexPos = 0; v[10] = 1;
} v[11] = 0;
si = addTwoVertex(v, si);
curVertices[vertexPos++] = (short) ((x - uxw) * SCALE_FACTOR);
curVertices[vertexPos++] = (short) ((y - uyw) * SCALE_FACTOR);
curVertices[vertexPos++] = 1;
curVertices[vertexPos++] = 0;
prevX = x; prevX = x;
prevY = y; prevY = y;
@ -305,105 +295,71 @@ class LineLayer {
ux = vy; ux = vy;
uy = -vx; uy = -vx;
uxw = ux * w; uxw = ux;
uyw = uy * w; uyw = uy;
vxw = vx * w; vxw = vx;
vyw = vy * w; vyw = vy;
// outside = (x <= 0 || x >= Tile.TILE_SIZE || y <= 0 || y >= Tile.TILE_SIZE) outside = (x <= 0 || x >= tsize || y <= 0 || y >= tsize)
// && (x - vxw <= 0 || x - vxw >= Tile.TILE_SIZE || y - vyw <= 0 || y - vyw >= Tile.TILE_SIZE); && (x - vxw <= 0 || x - vxw >= tsize || y - vyw <= 0 || y - vyw >= tsize);
if (vertexPos == MAX) { v[0] = (short) (x * S);
curVertices = getNextItem(); v[1] = (short) (y * S);
vertexPos = 0;
}
if (rounded && !outside) { if (rounded && !outside) {
curVertices[vertexPos++] = (short) ((x + uxw) * SCALE_FACTOR); v[2] = (short) ((uxw) * S1000);
curVertices[vertexPos++] = (short) ((y + uyw) * SCALE_FACTOR); v[3] = (short) ((uyw) * S1000);
curVertices[vertexPos++] = -1; v[4] = -1;
curVertices[vertexPos++] = 0; v[5] = 0;
si = addVertex(v, si);
if (vertexPos == MAX) { v[2] = (short) ((-uxw) * S1000);
curVertices = getNextItem(); v[3] = (short) ((-uyw) * S1000);
vertexPos = 0; v[4] = 1;
} v[5] = 0;
si = addVertex(v, si);
curVertices[vertexPos++] = (short) ((x - uxw) * SCALE_FACTOR);
curVertices[vertexPos++] = (short) ((y - uyw) * SCALE_FACTOR);
curVertices[vertexPos++] = 1;
curVertices[vertexPos++] = 0;
if (vertexPos == MAX) {
curVertices = getNextItem();
vertexPos = 0;
}
// For rounded line edges // For rounded line edges
curVertices[vertexPos++] = (short) ((x + uxw - vxw) * SCALE_FACTOR); v[2] = (short) ((uxw - vxw) * S1000);
curVertices[vertexPos++] = (short) ((y + uyw - vyw) * SCALE_FACTOR); v[3] = (short) ((uyw - vyw) * S1000);
curVertices[vertexPos++] = -1; v[4] = -1;
curVertices[vertexPos++] = -1; v[5] = -1;
si = addVertex(v, si);
if (vertexPos == MAX) { v[2] = (short) (-(uxw + vxw) * S1000);
curVertices = getNextItem(); v[3] = (short) (-(uyw + vyw) * S1000);
vertexPos = 0; v[4] = 1;
} v[5] = -1;
si = addVertex(v, si);
// Add the last vertex twice to be able to draw with GL_TRIANGLE_STRIP si = addVertex(v, si);
curVertices[vertexPos++] = (short) ((x - uxw - vxw) * SCALE_FACTOR);
curVertices[vertexPos++] = (short) ((y - uyw - vyw) * SCALE_FACTOR);
curVertices[vertexPos++] = 1;
curVertices[vertexPos++] = -1;
if (vertexPos == MAX) {
curVertices = getNextItem();
vertexPos = 0;
}
curVertices[vertexPos++] = (short) ((x - uxw - vxw) * SCALE_FACTOR);
curVertices[vertexPos++] = (short) ((y - uyw - vyw) * SCALE_FACTOR);
curVertices[vertexPos++] = 1;
curVertices[vertexPos++] = -1;
} else { } else {
if (!outside) { if (squared) {
vxw = 0;
vyw = 0;
} else if (!outside) {
vxw *= 0.5; vxw *= 0.5;
vyw *= 0.5; vyw *= 0.5;
} }
if (rounded) {
if (rounded)
verticesCnt -= 2; verticesCnt -= 2;
v[2] = (short) ((uxw) * S1000);
v[3] = (short) ((uyw) * S1000);
v[4] = -1;
v[5] = 0;
si = addVertex(v, si);
v[2] = (short) (-(uxw + vxw) * S1000);
v[3] = (short) (-(uyw + vyw) * S1000);
v[4] = 1;
v[5] = 0;
si = addVertex(v, si);
si = addVertex(v, si);
} }
curVertices[vertexPos++] = (short) ((x + uxw) * SCALE_FACTOR); curItem = si;
curVertices[vertexPos++] = (short) ((y + uyw) * SCALE_FACTOR);
curVertices[vertexPos++] = -1;
curVertices[vertexPos++] = 0;
if (vertexPos == MAX) {
curVertices = getNextItem();
vertexPos = 0;
}
// Add the last vertex twice to be able to draw with GL_TRIANGLE_STRIP
curVertices[vertexPos++] = (short) ((x - uxw - vxw) * SCALE_FACTOR);
curVertices[vertexPos++] = (short) ((y - uyw - vyw) * SCALE_FACTOR);
curVertices[vertexPos++] = 1;
curVertices[vertexPos++] = 0;
if (vertexPos == MAX) {
curVertices = getNextItem();
vertexPos = 0;
}
curVertices[vertexPos++] = (short) ((x - uxw - vxw) * SCALE_FACTOR);
curVertices[vertexPos++] = (short) ((y - uyw - vyw) * SCALE_FACTOR);
curVertices[vertexPos++] = 1;
curVertices[vertexPos++] = 0;
}
curItem.used = vertexPos;
} }
} }

View File

@ -14,136 +14,167 @@
*/ */
package org.mapsforge.android.glrenderer; package org.mapsforge.android.glrenderer;
import java.nio.ByteBuffer; import static android.opengl.GLES20.GL_TRIANGLE_STRIP;
import java.nio.ByteOrder; import static android.opengl.GLES20.glDisableVertexAttribArray;
import static android.opengl.GLES20.glDrawArrays;
import static android.opengl.GLES20.glEnableVertexAttribArray;
import static android.opengl.GLES20.glGetAttribLocation;
import static android.opengl.GLES20.glGetUniformLocation;
import static android.opengl.GLES20.glUniform4f;
import static android.opengl.GLES20.glUniform4fv;
import static android.opengl.GLES20.glUniformMatrix4fv;
import static android.opengl.GLES20.glUseProgram;
import static android.opengl.GLES20.glVertexAttribPointer;
import java.nio.ShortBuffer; import java.nio.ShortBuffer;
import org.mapsforge.android.rendertheme.renderinstruction.Line;
import org.mapsforge.android.utils.GlUtils;
import android.opengl.GLES20;
import android.util.FloatMath;
class LineLayers { class LineLayers {
private static int NUM_VERTEX_FLOATS = 4; private static int NUM_VERTEX_SHORTS = 6;
// static FloatBuffer compileLayerData(LineLayer layers, FloatBuffer buf) { private static final int LINE_VERTICES_DATA_POS_OFFSET = 0;
// FloatBuffer fbuf = buf; private static final int LINE_VERTICES_DATA_TEX_OFFSET = 8;
// int size = 0;
//
// for (LineLayer l = layers; l != null; l = l.next)
// size += l.verticesCnt;
//
// size *= NUM_VERTEX_FLOATS;
//
// if (buf == null || buf.capacity() < size) {
// ByteBuffer bbuf = ByteBuffer.allocateDirect(size * 4).order(
// ByteOrder.nativeOrder());
// fbuf = bbuf.asFloatBuffer();
// } else {
// fbuf.clear();
// }
// int pos = 0;
//
// PoolItem last = null, items = null;
//
// for (LineLayer l = layers; l != null; l = l.next) {
// if (l.isOutline)
// continue;
//
// for (PoolItem item = l.pool; item != null; item = item.next) {
// fbuf.put(item.vertices, 0, item.used);
// last = item;
// }
// l.offset = pos;
// pos += l.verticesCnt;
//
// if (last != null) {
// last.next = items;
// items = l.pool;
// }
//
// l.pool = null;
// }
//
// VertexPool.add(items);
//
// fbuf.flip();
//
// return fbuf;
// }
//
// static ShortBuffer compileLayerData(LineLayer layers, ShortBuffer buf) {
// int size = 0;
// ShortBuffer sbuf = buf;
//
// for (LineLayer l = layers; l != null; l = l.next)
// size += l.verticesCnt;
//
// size *= NUM_VERTEX_FLOATS;
//
// if (buf == null || buf.capacity() < size) {
// ByteBuffer bbuf = ByteBuffer.allocateDirect(size * 2).order(
// ByteOrder.nativeOrder());
// sbuf = bbuf.asShortBuffer();
// } else {
// sbuf.clear();
// }
// int pos = 0;
//
// short[] data = new short[PoolItem.SIZE];
//
// PoolItem last = null, items = null;
//
// for (LineLayer l = layers; l != null; l = l.next) {
// if (l.isOutline)
// continue;
//
// for (PoolItem item = l.pool; item != null; item = item.next) {
// PoolItem.toHalfFloat(item, data);
// sbuf.put(data, 0, item.used);
// last = item;
// }
//
// l.offset = pos;
// pos += l.verticesCnt;
//
// if (last != null) {
// last.next = items;
// items = l.pool;
// }
//
// l.pool = null;
// }
//
// VertexPool.add(items);
//
// sbuf.flip();
//
// return sbuf;
// }
//
// static void clear(LineLayer layer) {
// for (LineLayer l = layer; l != null; l = l.next) {
// if (l.pool != null)
// VertexPool.add(l.pool);
// }
// }
static ShortBuffer compileLayerData(LineLayer layers, ShortBuffer buf) { // shader handles
private static int lineProgram;
private static int hLineVertexPosition;
private static int hLineTexturePosition;
private static int hLineColor;
private static int hLineMatrix;
private static int hLineScale;
private static int hLineWidth;
static boolean init() {
lineProgram = GlUtils.createProgram(Shaders.lineVertexShader,
Shaders.lineFragmentShader);
if (lineProgram == 0) {
// Log.e(TAG, "Could not create line program.");
return false;
}
hLineMatrix = glGetUniformLocation(lineProgram, "mvp");
hLineScale = glGetUniformLocation(lineProgram, "u_wscale");
hLineWidth = glGetUniformLocation(lineProgram, "u_width");
hLineColor = glGetUniformLocation(lineProgram, "u_color");
hLineVertexPosition = GLES20.glGetAttribLocation(lineProgram, "a_position");
hLineTexturePosition = glGetAttribLocation(lineProgram, "a_st");
return true;
}
static LineLayer drawLines(GLMapTile tile, LineLayer layer, int next, float[] matrix,
float div, double zoom, float scale) {
float z = 1 / div;
if (layer == null)
return null;
glUseProgram(lineProgram);
glEnableVertexAttribArray(hLineVertexPosition);
glEnableVertexAttribArray(hLineTexturePosition);
glVertexAttribPointer(hLineVertexPosition, 4, GLES20.GL_SHORT,
false, 12, tile.lineOffset + LINE_VERTICES_DATA_POS_OFFSET);
glVertexAttribPointer(hLineTexturePosition, 2, GLES20.GL_SHORT,
false, 12, tile.lineOffset + LINE_VERTICES_DATA_TEX_OFFSET);
glUniformMatrix4fv(hLineMatrix, 1, false, matrix, 0);
// if (diff != 0)
// // diff < 0 means tile is parent
// z = (diff > 0) ? 1.0f / (1 << diff) : (1 << -diff);
// scale factor to map one pixel on tile to one pixel on screen:
// float pixel = 2.0f / (scale * z);
// GLES20.glUniform1f(hLineScale, pixel);
// line scale factor (for non fixed lines)
float s = FloatMath.sqrt(scale * z);
boolean blur = false;
GLES20.glUniform1f(hLineScale, 0);
LineLayer l = layer;
for (; l != null && l.layer < next; l = l.next) {
Line line = l.line;
if (line.fade != -1 && line.fade > zoom)
continue;
if (line.fade >= zoom) {
float alpha = 1.0f;
alpha = (scale > 1.2f ? scale : 1.2f) - alpha;
if (alpha > 1.0f)
alpha = 1.0f;
glUniform4f(hLineColor,
line.color[0], line.color[1], line.color[2], alpha);
} else {
glUniform4fv(hLineColor, 1, line.color, 0);
}
if (blur) {
GLES20.glUniform1f(hLineScale, 0);
blur = false;
}
if (l.isOutline) {
for (LineLayer o = l.outlines; o != null; o = o.outlines) {
if (line.blur != 0) {
GLES20.glUniform1f(hLineScale, (l.width + o.width) / (scale * z)
- (line.blur / (scale * z)));
blur = true;
}
if (zoom > MapGenerator.STROKE_MAX_ZOOM_LEVEL)
GLES20.glUniform1f(hLineWidth,
(l.width + o.width) / (scale * z));
else
GLES20.glUniform1f(hLineWidth, l.width / (scale * z)
+ o.width / s);
glDrawArrays(GL_TRIANGLE_STRIP, o.offset, o.verticesCnt);
}
}
else {
if (line.blur != 0) {
GLES20.glUniform1f(hLineScale, (l.width / s) * line.blur);
blur = true;
}
if (line.fixed || zoom > MapGenerator.STROKE_MAX_ZOOM_LEVEL) {
// invert scaling of extrusion vectors so that line width stays the same
GLES20.glUniform1f(hLineWidth, (l.width / (scale * z)));
} else {
GLES20.glUniform1f(hLineWidth, (l.width / s));
}
glDrawArrays(GL_TRIANGLE_STRIP, l.offset, l.verticesCnt);
}
}
glDisableVertexAttribArray(hLineVertexPosition);
glDisableVertexAttribArray(hLineTexturePosition);
return l;
}
static int sizeOf(LineLayer layers) {
int size = 0; int size = 0;
ShortBuffer sbuf = buf;
for (LineLayer l = layers; l != null; l = l.next) for (LineLayer l = layers; l != null; l = l.next)
size += l.verticesCnt; size += l.verticesCnt;
size *= NUM_VERTEX_FLOATS; size *= NUM_VERTEX_SHORTS;
return size;
if (buf == null || buf.capacity() < size) {
ByteBuffer bbuf = ByteBuffer.allocateDirect(size * 2).order(
ByteOrder.nativeOrder());
sbuf = bbuf.asShortBuffer();
} else {
sbuf.clear();
} }
static void compileLayerData(LineLayer layers, ShortBuffer sbuf) {
int pos = 0; int pos = 0;
// short[] data = new short[PoolItem.SIZE];
ShortItem last = null, items = null; ShortItem last = null, items = null;
for (LineLayer l = layers; l != null; l = l.next) { for (LineLayer l = layers; l != null; l = l.next) {
@ -151,8 +182,6 @@ class LineLayers {
continue; continue;
for (ShortItem item = l.pool; item != null; item = item.next) { for (ShortItem item = l.pool; item != null; item = item.next) {
// PoolItem.toHalfFloat(item, data);
// sbuf.put(data, 0, item.used);
sbuf.put(item.vertices, 0, item.used); sbuf.put(item.vertices, 0, item.used);
last = item; last = item;
} }
@ -166,19 +195,110 @@ class LineLayers {
} }
l.pool = null; l.pool = null;
l.curItem = null;
} }
ShortPool.add(items); ShortPool.add(items);
sbuf.flip();
return sbuf;
} }
// @SuppressLint("UseValueOf")
// private static final Boolean lock = new Boolean(true);
// private static final int POOL_LIMIT = 1500;
//
// static private LineLayer pool = null;
// static private int count = 0;
// static private int countAll = 0;
//
// static void finish() {
// synchronized (lock) {
// count = 0;
// countAll = 0;
// pool = null;
// }
// }
//
// static LineLayer get(int layer, Line line, float width, boolean outline) {
// synchronized (lock) {
//
// if (count == 0 && pool == null) {
// countAll++;
// return new LineLayer(layer, line, width, outline);
// }
// if (count > 0) {
// count--;
// } else {
// int c = 0;
// LineLayer tmp = pool;
//
// while (tmp != null) {
// c++;
// tmp = tmp.next;
// }
//
// Log.d("LineLayersl", "eek wrong count: " + c + " left");
// }
//
// LineLayer it = pool;
// pool = pool.next;
// it.next = null;
// it.layer = layer;
// it.line = line;
// it.isOutline = outline;
// it.width = width;
// return it;
// }
// }
//
// static void add(LineLayer layers) {
// if (layers == null)
// return;
//
// synchronized (lock) {
//
// // limit pool items
// if (countAll < POOL_LIMIT) {
// LineLayer last = layers;
//
// while (true) {
// count++;
//
// if (last.next == null)
// break;
//
// last = last.next;
// }
//
// last.next = pool;
// pool = layers;
//
// } else {
// int cleared = 0;
// LineLayer prev, tmp = layers;
// while (tmp != null) {
// prev = tmp;
// tmp = tmp.next;
//
// countAll--;
// cleared++;
//
// prev.next = null;
//
// }
// Log.d("LineLayers", "sum: " + countAll + " free: " + count + " freed "
// + cleared);
// }
//
// }
// }
//
static void clear(LineLayer layer) { static void clear(LineLayer layer) {
for (LineLayer l = layer; l != null; l = l.next) { for (LineLayer l = layer; l != null; l = l.next) {
if (l.pool != null) if (l.pool != null) {
ShortPool.add(l.pool); ShortPool.add(l.pool);
l.pool = null;
l.curItem = null;
} }
} }
// LineLayers.add(layer);
}
} }

View File

@ -14,8 +14,6 @@
*/ */
package org.mapsforge.android.glrenderer; package org.mapsforge.android.glrenderer;
import java.util.ArrayList;
import org.mapsforge.android.mapgenerator.IMapGenerator; import org.mapsforge.android.mapgenerator.IMapGenerator;
import org.mapsforge.android.mapgenerator.MapGeneratorJob; import org.mapsforge.android.mapgenerator.MapGeneratorJob;
import org.mapsforge.android.rendertheme.IRenderCallback; import org.mapsforge.android.rendertheme.IRenderCallback;
@ -23,6 +21,7 @@ import org.mapsforge.android.rendertheme.RenderTheme;
import org.mapsforge.android.rendertheme.renderinstruction.Area; import org.mapsforge.android.rendertheme.renderinstruction.Area;
import org.mapsforge.android.rendertheme.renderinstruction.Caption; import org.mapsforge.android.rendertheme.renderinstruction.Caption;
import org.mapsforge.android.rendertheme.renderinstruction.Line; import org.mapsforge.android.rendertheme.renderinstruction.Line;
import org.mapsforge.android.rendertheme.renderinstruction.PathText;
import org.mapsforge.android.rendertheme.renderinstruction.RenderInstruction; import org.mapsforge.android.rendertheme.renderinstruction.RenderInstruction;
import org.mapsforge.core.MercatorProjection; import org.mapsforge.core.MercatorProjection;
import org.mapsforge.core.Tag; import org.mapsforge.core.Tag;
@ -46,11 +45,11 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
private static final double PI180 = (Math.PI / 180) / 1000000.0; private static final double PI180 = (Math.PI / 180) / 1000000.0;
private static final double PIx4 = Math.PI * 4; private static final double PIx4 = Math.PI * 4;
private static final double STROKE_INCREASE = Math.sqrt(2); private static final double STROKE_INCREASE = Math.sqrt(2);
private static final byte STROKE_MIN_ZOOM_LEVEL = 12;
private static final byte LAYERS = 11; private static final byte LAYERS = 11;
private static final double f900913 = 20037508.342789244; private static final double f900913 = 20037508.342789244;
// 134217728
// 2147483648.000 static final byte STROKE_MIN_ZOOM_LEVEL = 12;
static final byte STROKE_MAX_ZOOM_LEVEL = 17;
private static RenderTheme renderTheme; private static RenderTheme renderTheme;
@ -66,14 +65,23 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
private LineLayer mCurLineLayer; private LineLayer mCurLineLayer;
private PolygonLayer mCurPolyLayer; private PolygonLayer mCurPolyLayer;
private ArrayList<TextItem> mLabels; private TextItem mLabels;
private int mDrawingLayer; private int mDrawingLayer;
private int mLevels; private int mLevels;
private boolean useSphericalMercator = false;
private float mStrokeScale = 1.0f; private float mStrokeScale = 1.0f;
private boolean mProjected;
// private boolean mProjectedResult;
private float mSimplify;
// private boolean firstMatch;
// private boolean prevClosed;
private RenderInstruction[] mRenderInstructions = null;
private final String TAG_WATER = "water".intern();
/** /**
* *
*/ */
@ -84,25 +92,29 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
private float mPoiX = 256; private float mPoiX = 256;
private float mPoiY = 256; private float mPoiY = 256;
private Tag mTagEmptyName = new Tag("name", ""); private Tag mTagEmptyName = new Tag(Tag.TAG_KEY_NAME, null, false);
private Tag mTagName; private Tag mTagName;
private void filterTags(Tag[] tags) { private void filterTags(Tag[] tags) {
for (int i = 0; i < tags.length; i++) { for (int i = 0; i < tags.length; i++) {
// Log.d(TAG, "check tag: " + tags[i]); // Log.d(TAG, "check tag: " + tags[i]);
if (tags[i].key == mTagEmptyName.key && tags[i].value != null) { if (tags[i].key == Tag.TAG_KEY_NAME && tags[i].value != null) {
mTagName = tags[i]; mTagName = tags[i];
tags[i] = mTagEmptyName; tags[i] = mTagEmptyName;
} }
} }
} }
// private RenderInstruction[] mNodeRenderInstructions;
@Override @Override
public void renderPointOfInterest(byte layer, float latitude, float longitude, public void renderPointOfInterest(byte layer, float latitude, float longitude,
Tag[] tags) { Tag[] tags) {
mTagName = null; mTagName = null;
if (mMapProjection != null)
{
long x = mCurrentTile.x; long x = mCurrentTile.x;
long y = mCurrentTile.y; long y = mCurrentTile.y;
long z = Tile.TILE_SIZE << mCurrentTile.zoomLevel; long z = Tile.TILE_SIZE << mCurrentTile.zoomLevel;
@ -111,11 +123,11 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
long dx = (x - (z >> 1)); long dx = (x - (z >> 1));
long dy = (y - (z >> 1)); long dy = (y - (z >> 1));
if (useSphericalMercator) { if (mMapProjection == WebMercator.NAME) {
divx = f900913 / (z >> 1); double div = f900913 / (z >> 1);
divy = f900913 / (z >> 1); // divy = f900913 / (z >> 1);
mPoiX = (float) (longitude / divx - dx); mPoiX = (float) (longitude / div - dx);
mPoiY = (float) (latitude / divy + dy); mPoiY = (float) (latitude / div + dy);
} else { } else {
divx = 180000000.0 / (z >> 1); divx = 180000000.0 / (z >> 1);
divy = z / PIx4; divy = z / PIx4;
@ -126,11 +138,16 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
|| mPoiY > Tile.TILE_SIZE + 10) || mPoiY > Tile.TILE_SIZE + 10)
return; return;
} }
} else {
mPoiX = longitude;
mPoiY = latitude;
}
// remove tags that should not be cached in Rendertheme // remove tags that should not be cached in Rendertheme
filterTags(tags); filterTags(tags);
// Log.d(TAG, "renderPointOfInterest: " + mTagName); // Log.d(TAG, "renderPointOfInterest: " + mTagName);
// mNodeRenderInstructions =
MapGenerator.renderTheme.matchNode(this, tags, mCurrentTile.zoomLevel); MapGenerator.renderTheme.matchNode(this, tags, mCurrentTile.zoomLevel);
} }
@ -140,82 +157,6 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
} }
private boolean mProjected;
private boolean mProjectedResult;
private float mSimplify;
private boolean projectToTile() {
if (mProjected)
return mProjectedResult;
float[] coords = mWayNodes;
long x = mCurrentTile.x;
long y = mCurrentTile.y;
long z = Tile.TILE_SIZE << mCurrentTile.zoomLevel;
float min = mSimplify;
double divx, divy;
long dx = (x - (z >> 1));
long dy = (y - (z >> 1));
if (useSphericalMercator) {
divx = f900913 / (z >> 1);
divy = f900913 / (z >> 1);
} else {
divx = 180000000.0 / (z >> 1);
divy = z / PIx4;
}
for (int pos = 0, outPos = 0, i = 0, m = mWays.length; i < m; i++) {
int len = mWays[i];
if (len == 0)
continue;
int cnt = 0;
float lat, lon, prevLon = 0, prevLat = 0;
for (int end = pos + len; pos < end; pos += 2) {
if (useSphericalMercator) {
lon = (float) (coords[pos] / divx - dx);
lat = (float) (coords[pos + 1] / divy + dy);
} else {
lon = (float) ((coords[pos]) / divx - dx);
double sinLat = Math.sin(coords[pos + 1] * PI180);
lat = (float) (Math.log((1.0 + sinLat) / (1.0 - sinLat)) * divy + dy);
}
if (cnt != 0) {
// drop small distance intermediate nodes
if (lat == prevLat && lon == prevLon)
continue;
if ((pos != end - 2) &&
!((lat > prevLat + min || lat < prevLat - min) ||
(lon > prevLon + min || lon < prevLon - min)))
continue;
}
coords[outPos++] = prevLon = lon;
coords[outPos++] = prevLat = lat;
cnt += 2;
}
mWays[i] = (short) cnt;
}
mProjected = true;
mProjectedResult = true;
return true;
}
// private boolean firstMatch;
// private boolean prevClosed;
private RenderInstruction[] mRenderInstructions = null;
private final String TAG_WATER = "water".intern();
@Override @Override
public void renderWay(byte layer, Tag[] tags, float[] wayNodes, short[] wayLength, public void renderWay(byte layer, Tag[] tags, float[] wayNodes, short[] wayLength,
boolean closed) { boolean closed) {
@ -239,6 +180,9 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
mWayNodes = wayNodes; mWayNodes = wayNodes;
mWays = wayLength; mWays = wayLength;
// remove tags that should not be cached in Rendertheme
filterTags(tags);
// if (mRenderInstructions != null) { // if (mRenderInstructions != null) {
// for (int i = 0, n = mRenderInstructions.length; i < n; i++) // for (int i = 0, n = mRenderInstructions.length; i < n; i++)
// mRenderInstructions[i].renderWay(this, tags); // mRenderInstructions[i].renderWay(this, tags);
@ -266,7 +210,6 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
mRenderInstructions = MapGenerator.renderTheme.matchWay(this, debugTagWay, mRenderInstructions = MapGenerator.renderTheme.matchWay(this, debugTagWay,
(byte) 0, true, true); (byte) 0, true, true);
} }
} }
@Override @Override
@ -277,9 +220,10 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
return; return;
if (caption.textKey == mTagEmptyName.key) { if (caption.textKey == mTagEmptyName.key) {
if (mLabels == null)
mLabels = new ArrayList<TextItem>(); TextItem t = new TextItem(mWayNodes[0], mWayNodes[1], mTagName.value, caption);
mLabels.add(new TextItem(mWayNodes[0], mWayNodes[1], mTagName.value, caption)); t.next = mLabels;
mLabels = t;
} }
} }
@ -292,9 +236,23 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
return; return;
if (caption.textKey == mTagEmptyName.key) { if (caption.textKey == mTagEmptyName.key) {
if (mLabels == null) TextItem t = new TextItem(mPoiX, mPoiY, mTagName.value, caption);
mLabels = new ArrayList<TextItem>(); t.next = mLabels;
mLabels.add(new TextItem(mPoiX, mPoiY, mTagName.value, caption)); mLabels = t;
}
}
@Override
public void renderWayText(PathText pathText) {
// Log.d(TAG, "renderWayText: " + mTagName);
if (mTagName == null)
return;
if (pathText.textKey == mTagEmptyName.key) {
mLabels = WayDecorator.renderText(mWayNodes, mTagName.value, pathText, 0,
mWays[0], mLabels);
} }
} }
@ -320,13 +278,23 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
private int countNodes; private int countNodes;
@Override @Override
public void renderWay(Line line) { public void renderWay(Line line, int level) {
projectToTile(); projectToTile();
LineLayer outlineLayer = null; if (line.outline && mCurLineLayer == null)
return;
float w = line.width;
if (!line.fixed) {
w *= mStrokeScale;
w *= mProjectionScaleFactor;
}
LineLayer lineLayer = null; LineLayer lineLayer = null;
int numLayer = mDrawingLayer + line.level; int numLayer = mDrawingLayer + level;
LineLayer l = mLineLayers; LineLayer l = mLineLayers;
@ -334,7 +302,9 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
lineLayer = mCurLineLayer; lineLayer = mCurLineLayer;
} else if (l == null || l.layer > numLayer) { } else if (l == null || l.layer > numLayer) {
// insert new layer at start // insert new layer at start
lineLayer = new LineLayer(numLayer, line, false); lineLayer = new LineLayer(numLayer, line, w, line.outline);
// lineLayer = LineLayers.get(numLayer, line, w, false);
lineLayer.next = l; lineLayer.next = l;
mLineLayers = lineLayer; mLineLayers = lineLayer;
} else { } else {
@ -346,7 +316,8 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
} }
// insert new layer between current and next layer // insert new layer between current and next layer
if (l.next == null || l.next.layer > numLayer) { if (l.next == null || l.next.layer > numLayer) {
lineLayer = new LineLayer(numLayer, line, false); lineLayer = new LineLayer(numLayer, line, w, line.outline);
// lineLayer = LineLayers.get(numLayer, line, w, false);
lineLayer.next = l.next; lineLayer.next = l.next;
l.next = lineLayer; l.next = lineLayer;
} }
@ -357,77 +328,83 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
if (lineLayer == null) if (lineLayer == null)
return; return;
if (line.outline) {
lineLayer.addOutline(mCurLineLayer);
return;
}
mCurLineLayer = lineLayer; mCurLineLayer = lineLayer;
float w = line.strokeWidth; boolean round = line.round;
if (!line.fixed) {
w *= mStrokeScale;
w *= mProjectionScaleFactor;
}
else {
w *= 1.2; // TODO make this dependent on dpi
}
for (int i = 0, pos = 0, n = mWays.length; i < n; i++) { for (int i = 0, pos = 0, n = mWays.length; i < n; i++) {
int length = mWays[i]; int length = mWays[i];
if (length < 0)
break;
// save some vertices
if (round && i > 200) {
// Log.d(TAG, "WAY TOO MANY LINES!!!");
round = false;
}
// need at least two points // need at least two points
if (length >= 4) { if (length >= 4) {
lineLayer.addLine(mWayNodes, pos, length, w, line.round); lineLayer.addLine(mWayNodes, pos, length);
countLines++; countLines++;
countNodes += length; countNodes += length;
} }
pos += length; pos += length;
} }
if (line.outline < 0) // if (line.outline < 0)
return; // return;
//
Line outline = MapGenerator.renderTheme.getOutline(line.outline); // Line outline = MapGenerator.renderTheme.getOutline(line.outline);
//
if (outline == null) // if (outline == null)
return; // return;
//
numLayer = mDrawingLayer + outline.level; // numLayer = mDrawingLayer + outline.getLevel();
//
l = mLineLayers; // l = mLineLayers;
//
if (l == null || l.layer > numLayer) { // if (l == null || l.layer > numLayer) {
// insert new layer at start // // insert new layer at start
outlineLayer = new LineLayer(numLayer, outline, true); // outlineLayer = new LineLayer(numLayer, outline, w, true);
outlineLayer.next = l; // // outlineLayer = LineLayers.get(numLayer, outline, w, true);
mLineLayers = outlineLayer; // outlineLayer.next = l;
} else { // mLineLayers = outlineLayer;
while (l != null) { // } else {
if (l.layer == numLayer) { // while (l != null) {
outlineLayer = l; // if (l.layer == numLayer) {
break; // outlineLayer = l;
} // break;
// insert new layer between current and next layer // }
if (l.next == null || l.next.layer > numLayer) { // // insert new layer between current and next layer
outlineLayer = new LineLayer(numLayer, outline, true); // if (l.next == null || l.next.layer > numLayer) {
outlineLayer.next = l.next; // outlineLayer = new LineLayer(numLayer, outline, w, true);
l.next = outlineLayer; // // outlineLayer = LineLayers.get(numLayer, outline, w, true);
} // outlineLayer.next = l.next;
l = l.next; // l.next = outlineLayer;
} // }
} // l = l.next;
// }
if (outlineLayer != null) // }
outlineLayer.addOutline(lineLayer); //
// if (outlineLayer != null)
// outlineLayer.addOutline(lineLayer);
} }
@Override @Override
public void renderArea(Area area) { public void renderArea(Area area, int level) {
if (!mDebugDrawPolygons) if (!mDebugDrawPolygons)
return; return;
if (!projectToTile()) if (!mProjected && !projectToTile())
return; return;
int numLayer = mDrawingLayer + area.level; int numLayer = mDrawingLayer + level;
PolygonLayer layer = null; PolygonLayer layer = null;
PolygonLayer l = mPolyLayers; PolygonLayer l = mPolyLayers;
@ -463,6 +440,9 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
for (int i = 0, pos = 0, n = mWays.length; i < n; i++) { for (int i = 0, pos = 0, n = mWays.length; i < n; i++) {
int length = mWays[i]; int length = mWays[i];
if (length < 0)
break;
// need at least three points // need at least three points
if (length >= 6) if (length >= 6)
layer.addPolygon(mWayNodes, pos, length); layer.addPolygon(mWayNodes, pos, length);
@ -470,6 +450,7 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
pos += length; pos += length;
} }
// if (area.line != null)
} }
@Override @Override
@ -478,12 +459,6 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
} }
@Override
public void renderWayText(String text, Paint paint, Paint stroke) {
// TODO Auto-generated method stub
}
@Override @Override
public void cleanup() { public void cleanup() {
// TODO Auto-generated method stub // TODO Auto-generated method stub
@ -495,23 +470,27 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
@Override @Override
public boolean executeJob(MapGeneratorJob mapGeneratorJob) { public boolean executeJob(MapGeneratorJob mapGeneratorJob) {
GLMapTile tile;
if (mMapDatabase == null) if (mMapDatabase == null)
return false; return false;
useSphericalMercator = WebMercator.NAME.equals(mMapDatabase.getMapProjection()); tile = mCurrentTile = (GLMapTile) mapGeneratorJob.tile;
mCurrentTile = (GLMapTile) mapGeneratorJob.tile;
mDebugDrawPolygons = !mapGeneratorJob.debugSettings.mDisablePolygons; mDebugDrawPolygons = !mapGeneratorJob.debugSettings.mDisablePolygons;
mDebugDrawUnmatched = mapGeneratorJob.debugSettings.mDrawUnmatchted; mDebugDrawUnmatched = mapGeneratorJob.debugSettings.mDrawUnmatchted;
if (mCurrentTile.isLoading || mCurrentTile.isReady)
if (tile.isLoading || tile.isReady || tile.isCanceled)
return false; return false;
mCurrentTile.isLoading = true; tile.isLoading = true;
mLevels = MapGenerator.renderTheme.getLevels(); mLevels = MapGenerator.renderTheme.getLevels();
setScaleStrokeWidth(mCurrentTile.zoomLevel); // limit stroke scale at z=17
if (tile.zoomLevel < STROKE_MAX_ZOOM_LEVEL)
setScaleStrokeWidth(tile.zoomLevel);
else
setScaleStrokeWidth(STROKE_MAX_ZOOM_LEVEL);
mLineLayers = null; mLineLayers = null;
mPolyLayers = null; mPolyLayers = null;
@ -520,43 +499,54 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
// firstMatch = true; // firstMatch = true;
countLines = 0; countLines = 0;
countNodes = 0; countNodes = 0;
mProjectionScaleFactor = (float) (1.0 / Math.cos(MercatorProjection
.pixelYToLatitude(mCurrentTile.pixelY, mCurrentTile.zoomLevel)
* (Math.PI / 180))); // / 1.5f;
if (mMapDatabase.executeQuery(mCurrentTile, this) != QueryResult.SUCCESS) { // acount for area changes with latitude
mProjectionScaleFactor = 0.5f + (float) (0.5 / Math.cos(MercatorProjection
.pixelYToLatitude(tile.pixelY, tile.zoomLevel)
* (Math.PI / 180)));
if (mMapDatabase.executeQuery(tile, this) != QueryResult.SUCCESS) {
Log.d(TAG, "Failed loading: " + tile);
LineLayers.clear(mLineLayers); LineLayers.clear(mLineLayers);
PolygonLayers.clear(mPolyLayers); PolygonLayers.clear(mPolyLayers);
mLineLayers = null; mLineLayers = null;
mPolyLayers = null; mPolyLayers = null;
mCurrentTile.isLoading = false; tile.isLoading = false;
return false; return false;
} }
if (mapGeneratorJob.debugSettings.mDrawTileFrames) { if (mapGeneratorJob.debugSettings.mDrawTileFrames) {
final float[] debugBoxCoords = { 0, 0, 0, Tile.TILE_SIZE,
Tile.TILE_SIZE, Tile.TILE_SIZE, Tile.TILE_SIZE, 0, 0, 0 };
final short[] debugBoxIndex = { 10 };
mTagName = new Tag("name", countLines + " " + countNodes + " " mTagName = new Tag("name", countLines + " " + countNodes + " "
+ mCurrentTile.toString(), false); + tile.toString(), false);
mPoiX = 10; mPoiX = Tile.TILE_SIZE >> 1;
mPoiY = 10; mPoiY = 10;
MapGenerator.renderTheme.matchNode(this, debugTagWay, (byte) 0); MapGenerator.renderTheme.matchNode(this, debugTagWay, (byte) 0);
// float[] coords = { 0, 0, 0, Tile.TILE_SIZE, Tile.TILE_SIZE, Tile.TILE_SIZE,
// Tile.TILE_SIZE, 0, 0, 0 }; mWays = debugBoxIndex;
// LineLayer ll = mLineLayers.getLayer(Integer.MAX_VALUE, Color.BLACK, false, mWayNodes = debugBoxCoords;
// true, -1); mDrawingLayer = 10 * mLevels;
// ll.addLine(coords, 0, coords.length, 1.5f, false); MapGenerator.renderTheme.matchWay(this, debugTagBox, (byte) 0, false, true);
} }
mCurrentTile.lineLayers = mLineLayers; tile.lineLayers = mLineLayers;
mCurrentTile.polygonLayers = mPolyLayers; tile.polygonLayers = mPolyLayers;
mCurrentTile.labels = mLabels; tile.labels = mLabels;
mCurPolyLayer = null; mCurPolyLayer = null;
mCurLineLayer = null; mCurLineLayer = null;
mCurrentTile.newData = true; tile.newData = true;
tile.isLoading = false;
return true; return true;
} }
private Tag[] debugTagWay = { new Tag("debug", "way") }; private final Tag[] debugTagBox = { new Tag("debug", "box") };
private Tag[] debugTagArea = { new Tag("debug", "area") }; private final Tag[] debugTagWay = { new Tag("debug", "way") };
private final Tag[] debugTagArea = { new Tag("debug", "area") };
private float mProjectionScaleFactor; private float mProjectionScaleFactor;
@ -586,9 +576,12 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
mStrokeScale = 1; mStrokeScale = 1;
} }
private String mMapProjection;
@Override @Override
public void setMapDatabase(IMapDatabase mapDatabase) { public void setMapDatabase(IMapDatabase mapDatabase) {
mMapDatabase = mapDatabase; mMapDatabase = mapDatabase;
mMapProjection = mMapDatabase.getMapProjection();
} }
@Override @Override
@ -609,4 +602,76 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
return mRenderInstructions != null; return mRenderInstructions != null;
} }
private boolean projectToTile() {
if (mProjected || mMapProjection == null)
return true;
boolean useWebMercator = false;
if (mMapProjection == WebMercator.NAME)
useWebMercator = true;
float[] coords = mWayNodes;
long x = mCurrentTile.x;
long y = mCurrentTile.y;
long z = Tile.TILE_SIZE << mCurrentTile.zoomLevel;
float min = mSimplify;
double divx, divy;
long dx = (x - (z >> 1));
long dy = (y - (z >> 1));
if (useWebMercator) {
divx = f900913 / (z >> 1);
divy = f900913 / (z >> 1);
} else {
divx = 180000000.0 / (z >> 1);
divy = z / PIx4;
}
for (int pos = 0, outPos = 0, i = 0, m = mWays.length; i < m; i++) {
int len = mWays[i];
if (len == 0)
continue;
if (len < 0)
break;
int cnt = 0;
float lat, lon, prevLon = 0, prevLat = 0;
for (int end = pos + len; pos < end; pos += 2) {
if (useWebMercator) {
lon = (float) (coords[pos] / divx - dx);
lat = (float) (coords[pos + 1] / divy + dy);
} else {
lon = (float) ((coords[pos]) / divx - dx);
double sinLat = Math.sin(coords[pos + 1] * PI180);
lat = (float) (Math.log((1.0 + sinLat) / (1.0 - sinLat)) * divy + dy);
}
if (cnt != 0) {
// drop small distance intermediate nodes
if (lat == prevLat && lon == prevLon)
continue;
if ((pos != end - 2) &&
!((lat > prevLat + min || lat < prevLat - min) ||
(lon > prevLon + min || lon < prevLon - min)))
continue;
}
coords[outPos++] = prevLon = lon;
coords[outPos++] = prevLat = lat;
cnt += 2;
}
mWays[i] = (short) cnt;
}
mProjected = true;
// mProjectedResult = true;
return true;
}
} }

File diff suppressed because it is too large Load Diff

View File

@ -15,11 +15,14 @@
package org.mapsforge.android.glrenderer; package org.mapsforge.android.glrenderer;
import org.mapsforge.android.rendertheme.renderinstruction.Area; import org.mapsforge.android.rendertheme.renderinstruction.Area;
import org.mapsforge.core.Tile;
class PolygonLayer { class PolygonLayer {
private static final float S = MapRenderer.COORD_MULTIPLIER;
PolygonLayer next; PolygonLayer next;
Area area; Area area;
private static final float SCALE_FACTOR = 16.0f; // private static final float MapRenderer.COORD_MULTIPLIER = 8.0f;
private boolean first = true; private boolean first = true;
private float originX; private float originX;
private float originY; private float originY;
@ -53,8 +56,8 @@ class PolygonLayer {
if (first) { if (first) {
first = false; first = false;
originX = points[pos]; originX = Tile.TILE_SIZE >> 1; // points[pos];
originY = points[pos + 1]; originY = Tile.TILE_SIZE >> 1; // points[pos + 1];
} }
short[] curVertices = curItem.vertices; short[] curVertices = curItem.vertices;
@ -65,24 +68,25 @@ class PolygonLayer {
outPos = 0; outPos = 0;
} }
curVertices[outPos++] = (short) (originX * SCALE_FACTOR); curVertices[outPos++] = (short) (originX * S);
curVertices[outPos++] = (short) (originY * SCALE_FACTOR); curVertices[outPos++] = (short) (originY * S);
int MAX = ShortItem.SIZE;
int remaining = length; int remaining = length;
int inPos = pos; int inPos = pos;
while (remaining > 0) { while (remaining > 0) {
if (outPos == ShortItem.SIZE) { if (outPos == MAX) {
curVertices = getNextItem(); curVertices = getNextItem();
outPos = 0; outPos = 0;
} }
int len = remaining; int len = remaining;
if (len > (ShortItem.SIZE) - outPos) if (len > MAX - outPos)
len = (ShortItem.SIZE) - outPos; len = MAX - outPos;
for (int i = 0; i < len; i++) for (int i = 0; i < len; i++)
curVertices[outPos++] = (short) (points[inPos++] * SCALE_FACTOR); curVertices[outPos++] = (short) (points[inPos++] * S);
// System.arraycopy(points, inPos, curVertices, outPos, len); // System.arraycopy(points, inPos, curVertices, outPos, len);
@ -92,13 +96,13 @@ class PolygonLayer {
remaining -= len; remaining -= len;
} }
if (outPos == PoolItem.SIZE) { if (outPos == MAX) {
curVertices = getNextItem(); curVertices = getNextItem();
outPos = 0; outPos = 0;
} }
curVertices[outPos++] = (short) (points[pos + 0] * SCALE_FACTOR); curVertices[outPos++] = (short) (points[pos + 0] * S);
curVertices[outPos++] = (short) (points[pos + 1] * SCALE_FACTOR); curVertices[outPos++] = (short) (points[pos + 1] * S);
curItem.used = outPos; curItem.used = outPos;
} }

View File

@ -14,172 +14,269 @@
*/ */
package org.mapsforge.android.glrenderer; package org.mapsforge.android.glrenderer;
import java.nio.ByteBuffer; import static android.opengl.GLES20.GL_BLEND;
import java.nio.ByteOrder; import static android.opengl.GLES20.GL_EQUAL;
import static android.opengl.GLES20.GL_INVERT;
import static android.opengl.GLES20.GL_KEEP;
import static android.opengl.GLES20.GL_NEVER;
import static android.opengl.GLES20.GL_STENCIL_TEST;
import static android.opengl.GLES20.GL_TRIANGLE_FAN;
import static android.opengl.GLES20.GL_TRIANGLE_STRIP;
import static android.opengl.GLES20.GL_ZERO;
import static android.opengl.GLES20.glColorMask;
import static android.opengl.GLES20.glDisable;
import static android.opengl.GLES20.glDrawArrays;
import static android.opengl.GLES20.glEnable;
import static android.opengl.GLES20.glEnableVertexAttribArray;
import static android.opengl.GLES20.glGetAttribLocation;
import static android.opengl.GLES20.glGetUniformLocation;
import static android.opengl.GLES20.glStencilFunc;
import static android.opengl.GLES20.glStencilMask;
import static android.opengl.GLES20.glStencilOp;
import static android.opengl.GLES20.glUniform4f;
import static android.opengl.GLES20.glUniform4fv;
import static android.opengl.GLES20.glUniformMatrix4fv;
import static android.opengl.GLES20.glUseProgram;
import static android.opengl.GLES20.glVertexAttribPointer;
import java.nio.ShortBuffer; import java.nio.ShortBuffer;
import org.mapsforge.core.Tile; import org.mapsforge.android.utils.GlUtils;
import android.opengl.GLES20;
class PolygonLayers { class PolygonLayers {
private static final int NUM_VERTEX_FLOATS = 2; private static final int NUM_VERTEX_SHORTS = 2;
// static final float[] mFillCoords = { -2, Tile.TILE_SIZE + 1, private static final int POLYGON_VERTICES_DATA_POS_OFFSET = 0;
// Tile.TILE_SIZE + 1, Tile.TILE_SIZE + 1, -2, private static int STENCIL_BITS = 8;
// -2, Tile.TILE_SIZE + 1, -2 };
// private static short[] mByteFillCoords = null; private static PolygonLayer[] mFillPolys;
// static FloatBuffer compileLayerData(PolygonLayer layers, FloatBuffer buf) { private static int polygonProgram;
// FloatBuffer fbuf = buf; private static int hPolygonVertexPosition;
// int size = 4; private static int hPolygonMatrix;
// private static int hPolygonColor;
// for (PolygonLayer l = layers; l != null; l = l.next)
// size += l.verticesCnt;
//
// size *= NUM_VERTEX_FLOATS;
//
// if (buf == null || buf.capacity() < size) {
// ByteBuffer bbuf = ByteBuffer.allocateDirect(size * 4).order(
// ByteOrder.nativeOrder());
// // Log.d("GLMap", "allocate buffer " + size);
// fbuf = bbuf.asFloatBuffer();
// } else {
// fbuf.clear();
// }
//
// fbuf.put(mFillCoords, 0, 8);
// int pos = 4;
//
// PoolItem last = null, items = null;
//
// for (PolygonLayer l = layers; l != null; l = l.next) {
//
// for (PoolItem item = l.pool; item != null; item = item.next) {
// fbuf.put(item.vertices, 0, item.used);
// last = item;
// }
// l.offset = pos;
// pos += l.verticesCnt;
//
// if (last != null) {
// last.next = items;
// items = l.pool;
// }
//
// l.pool = null;
// }
//
// VertexPool.add(items);
//
// fbuf.flip();
//
// return fbuf;
// }
//
// static final short[] tmpItem = new short[PoolItem.SIZE];
// static ShortBuffer compileLayerData(PolygonLayer layers, ShortBuffer buf) { static boolean init() {
// ShortBuffer sbuf = buf;
// int size = 4; // Set up the program for rendering polygons
polygonProgram = GlUtils.createProgram(Shaders.polygonVertexShader,
Shaders.polygonFragmentShader);
if (polygonProgram == 0) {
// Log.e(TAG, "Could not create polygon program.");
return false;
}
hPolygonMatrix = glGetUniformLocation(polygonProgram, "mvp");
hPolygonVertexPosition = glGetAttribLocation(polygonProgram, "a_position");
hPolygonColor = glGetUniformLocation(polygonProgram, "u_color");
mFillPolys = new PolygonLayer[STENCIL_BITS];
return true;
}
private static void fillPolygons(int count, double zoom, float scale) {
boolean blend = false;
// draw to framebuffer
glColorMask(true, true, true, true);
// do not modify stencil buffer
glStencilMask(0);
for (int c = 0; c < count; c++) {
PolygonLayer l = mFillPolys[c];
float alpha = 1.0f;
if (l.area.fade >= zoom || l.area.color[3] != 1.0) {
if (l.area.fade >= zoom) {
alpha = (scale > 1.3f ? scale : 1.3f) - alpha;
if (alpha > 1.0f)
alpha = 1.0f;
}
alpha *= l.area.color[3];
if (!blend) {
glEnable(GL_BLEND);
blend = true;
}
glUniform4f(hPolygonColor,
l.area.color[0], l.area.color[1], l.area.color[2], alpha);
} else if (l.area.blend == zoom) {
alpha = scale - 1.0f;
if (alpha > 1.0f)
alpha = 1.0f;
else if (alpha < 0)
alpha = 0;
glUniform4f(hPolygonColor,
l.area.color[0] * (1 - alpha) + l.area.blendColor[0] * alpha,
l.area.color[1] * (1 - alpha) + l.area.blendColor[1] * alpha,
l.area.color[2] * (1 - alpha) + l.area.blendColor[2] * alpha, 1);
} else {
if (blend) {
glDisable(GL_BLEND);
blend = false;
}
if (l.area.blend <= zoom && l.area.blend > 0)
glUniform4fv(hPolygonColor, 1, l.area.blendColor, 0);
else
glUniform4fv(hPolygonColor, 1, l.area.color, 0);
}
// set stencil buffer mask used to draw this layer
glStencilFunc(GL_EQUAL, 0xff, 1 << c);
// draw tile fill coordinates
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}
if (blend)
glDisable(GL_BLEND);
}
static PolygonLayer drawPolygons(PolygonLayer layer, int next,
float[] matrix, double zoom, float scale, short drawCount, boolean clip) {
int cnt = 0;
glUseProgram(polygonProgram);
glEnableVertexAttribArray(hPolygonVertexPosition);
glVertexAttribPointer(hPolygonVertexPosition, 2,
GLES20.GL_SHORT, false, 0,
POLYGON_VERTICES_DATA_POS_OFFSET);
glUniformMatrix4fv(hPolygonMatrix, 1, false, matrix, 0);
glEnable(GL_STENCIL_TEST);
PolygonLayer l = layer;
for (; l != null && l.layer < next; l = l.next) {
// fade out polygon layers (set in RederTheme)
if (l.area.fade > 0 && l.area.fade > zoom)
continue;
if (cnt == 0) {
// disable drawing to framebuffer
glColorMask(false, false, false, false);
// never pass the test, i.e. always apply first stencil op (sfail)
glStencilFunc(GL_NEVER, 0, 0xff);
// clear stencilbuffer
glStencilMask(0xFF);
// glClear(GL_STENCIL_BUFFER_BIT);
// clear stencilbuffer (tile region)
glStencilOp(GL_ZERO, GL_KEEP, GL_KEEP);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// stencil op for stencil method polygon drawing
glStencilOp(GL_INVERT, GL_KEEP, GL_KEEP);
}
mFillPolys[cnt] = l;
// set stencil mask to draw to
glStencilMask(1 << cnt++);
glDrawArrays(GL_TRIANGLE_FAN, l.offset, l.verticesCnt);
// draw up to 8 layers into stencil buffer
if (cnt == STENCIL_BITS) {
fillPolygons(cnt, zoom, scale);
cnt = 0;
}
}
if (cnt > 0)
fillPolygons(cnt, zoom, scale);
glDisable(GL_STENCIL_TEST);
if (clip) {
drawDepthClip(drawCount);
}
// required on GalaxyII, Android 2.3.3 (cant just VAA enable once...)
GLES20.glDisableVertexAttribArray(hPolygonVertexPosition);
return l;
}
// static void drawStencilClip(byte drawCount) {
// // set stencil mask for line drawing... HACK!!!
// glColorMask(false, false, false, false);
// //
// for (PolygonLayer l = layers; l != null; l = l.next) // int c = drawCount % 16;
// size += l.verticesCnt; // // never pass the test, i.e. always apply first stencil op (sfail)
// // glStencilFunc(GLES20.GL_NEVER, drawCount, 0);
// glStencilFunc(GLES20.GL_NEVER, flipdabit[c], 0);
// //
// size *= NUM_VERTEX_FLOATS; // // replace stencilbuffer
// glStencilMask(0xff);
// //
// if (buf == null || buf.capacity() < size) { // // set stencilbuffer for (tile region)
// ByteBuffer bbuf = ByteBuffer.allocateDirect(size * 2).order( // glStencilOp(GLES20.GL_REPLACE, GLES20.GL_KEEP, GLES20.GL_KEEP);
// ByteOrder.nativeOrder()); // glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// sbuf = bbuf.asShortBuffer();
// } else {
// sbuf.clear();
// }
// //
// short[] data = tmpItem; // glStencilFunc(GL_EQUAL, flipdabit[c], 0xff);
// // do not modify stencil buffer
// glStencilMask(0);
// //
// if (mByteFillCoords == null) { // glColorMask(true, true, true, true);
// mByteFillCoords = new short[8];
// FastMath.convertFloatToHalf(mFillCoords[0], mByteFillCoords, 0);
// FastMath.convertFloatToHalf(mFillCoords[1], mByteFillCoords, 1);
// FastMath.convertFloatToHalf(mFillCoords[2], mByteFillCoords, 2);
// FastMath.convertFloatToHalf(mFillCoords[3], mByteFillCoords, 3);
// FastMath.convertFloatToHalf(mFillCoords[4], mByteFillCoords, 4);
// FastMath.convertFloatToHalf(mFillCoords[5], mByteFillCoords, 5);
// FastMath.convertFloatToHalf(mFillCoords[6], mByteFillCoords, 6);
// FastMath.convertFloatToHalf(mFillCoords[7], mByteFillCoords, 7);
// }
//
// sbuf.put(mByteFillCoords, 0, 8);
// int pos = 4;
//
// PoolItem last = null, items = null;
//
// for (PolygonLayer l = layers; l != null; l = l.next) {
//
// for (PoolItem item = l.pool; item != null; item = item.next) {
// PoolItem.toHalfFloat(item, data);
// sbuf.put(data, 0, item.used);
// last = item;
// }
//
// l.offset = pos;
// pos += l.verticesCnt;
//
// if (last != null) {
// last.next = items;
// items = l.pool;
// }
//
// l.pool = null;
// }
//
// VertexPool.add(items);
//
// sbuf.flip();
//
// return sbuf;
// }
//
// static void clear(PolygonLayer layers) {
// for (PolygonLayer l = layers; l != null; l = l.next) {
// if (l.pool != null)
// VertexPool.add(l.pool);
// }
// } // }
private static short[] mFillCoords; // this only increases the chance for the stencil buffer clip to work
// should check for clipping with depth buffer or sth
// private static short[] flipdabit = {
// 255, 254, 253, 251,
// 247, 239, 223, 191,
// 127, 63, 252, 250,
// 249, 243, 231, 207 };
static ShortBuffer compileLayerData(PolygonLayer layers, ShortBuffer buf) { static void drawDepthClip(short drawCount) {
ShortBuffer sbuf = buf;
int size = 4; glColorMask(false, false, false, false);
glEnable(GLES20.GL_DEPTH_TEST);
glEnable(GLES20.GL_POLYGON_OFFSET_FILL);
// GLES20.GL_PO
GLES20.glPolygonOffset(0, drawCount);
// int i[] = new int[1];
// GLES20.glGetIntegerv(GLES20.GL_POLYGON_OFFSET_UNITS, i, 0);
// Log.d("...", "UNITS " + i[0]);
//
// System.out.println("set offset: " + drawCount);
GLES20.glDepthMask(true);
GLES20.glDepthFunc(GLES20.GL_ALWAYS);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
GLES20.glDepthMask(false);
glColorMask(true, true, true, true);
GLES20.glDepthFunc(GLES20.GL_EQUAL);
}
static int sizeOf(PolygonLayer layers) {
int size = 0;
for (PolygonLayer l = layers; l != null; l = l.next) for (PolygonLayer l = layers; l != null; l = l.next)
size += l.verticesCnt; size += l.verticesCnt;
size *= NUM_VERTEX_FLOATS; size *= NUM_VERTEX_SHORTS;
if (buf == null || buf.capacity() < size) { return size;
ByteBuffer bbuf = ByteBuffer.allocateDirect(size * 2).order(
ByteOrder.nativeOrder());
sbuf = bbuf.asShortBuffer();
} else {
sbuf.clear();
} }
if (mFillCoords == null) { static void compileLayerData(PolygonLayer layers, ShortBuffer sbuf) {
short min = (-2) << 4;
short max = (short) ((Tile.TILE_SIZE + 1) << 4);
mFillCoords = new short[8];
mFillCoords[0] = min;
mFillCoords[1] = max;
mFillCoords[2] = max;
mFillCoords[3] = max;
mFillCoords[4] = min;
mFillCoords[5] = min;
mFillCoords[6] = max;
mFillCoords[7] = min;
}
sbuf.put(mFillCoords, 0, 8);
int pos = 4; int pos = 4;
ShortItem last = null, items = null; ShortItem last = null, items = null;
@ -203,10 +300,6 @@ class PolygonLayers {
} }
ShortPool.add(items); ShortPool.add(items);
sbuf.flip();
return sbuf;
} }
static void clear(PolygonLayer layers) { static void clear(PolygonLayer layers) {

View File

@ -16,166 +16,141 @@
package org.mapsforge.android.glrenderer; package org.mapsforge.android.glrenderer;
class Shaders { class Shaders {
final static String gLineVertexShader = ""
final static String lineVertexShader = ""
+ "precision mediump float; \n" + "precision mediump float; \n"
+ "uniform mat4 u_center;" + "uniform mat4 mvp;"
+ "attribute vec4 a_position;" + "attribute vec4 a_position;"
+ "attribute vec2 a_st;" + "attribute vec2 a_st;"
+ "varying vec2 v_st;" + "varying vec2 v_st;"
+ "const vec4 scale = vec4(1.0/16.0, 1.0/16.0, 0.0, 1.0);"
+ "void main() {"
// + " gl_Position = u_center * vec4(a_position.x, a_position.y, 0.0, 1.0);"
// + " v_st = a_position.zw;"
+ " gl_Position = u_center * (scale * a_position);"
// + " gl_Position = u_center * a_position;"
+ " v_st = a_st;"
+ "}";
final static String gLineFragmentShader = ""
+ "#extension GL_OES_standard_derivatives : enable\n"
+ "precision mediump float;"
+ "uniform lowp vec2 u_mode;"
+ "uniform vec4 u_color;"
+ "const lowp float zero = 0.0;"
+ "const float fuzzf = 1.8;"
+ "varying vec2 v_st;"
+ "void main() {"
+ " lowp vec4 color = u_color;"
+ " lowp float len;"
+ " lowp float fuzz;"
+ " lowp float width = u_mode[1];"
// + " if (v_st.t == zero){ "
// + " fuzz = fwidth(v_st.s) * fuzzf;"
// + " len = width - abs(v_st.s);"
// + " } else {"
+ " fuzz = max(fwidth(v_st.s), fwidth(v_st.t)) * fuzzf;"
+ " len = width - length(v_st);"
// + " } "
// + " if (len < min_fuzz)"
// + " discard;"
// + " alpha = zero;"
+ " if (len < fuzz) {"
+ " lowp float min_fuzz = -fuzz * u_mode[0];"
+ " color.a *= smoothstep(min_fuzz, fuzz, len);"
// + " if (color.a == 0.0 ) color = vec4(1.0,0.0,0.0,1.0);"
+ " }"
+ " gl_FragColor = color;"
+ "}";
// final static String gLineFragmentShader = ""
// + "#extension GL_OES_standard_derivatives : enable\n"
// + "#pragma profilepragma blendoperation(gl_FragColor, GL_FUNC_ADD, GL_ONE, GL_ONE_MINUS_SRC_ALPHA)\n"
// + "precision mediump float;"
// + "uniform vec2 u_mode;"
// + "uniform vec4 u_color;"
// + "const float zero = 0.0;"
// + "const vec4 blank = vec4(0.0,0.0,0.0,0.0);"
// + "varying vec2 v_st;"
// + "void main() {"
// + "lowp color = u_color;"
// + "lowp alpha = 1.0;"
// + "float width = u_mode[1];"
// + " if (v_st.t == zero){ "
// + " float fuzz = fwidth(v_st.s) * 1.5;"
// + " float min_fuzz = -fuzz * u_mode[0];"
// + " float len = width - abs(v_st.s);"
// // + " if (len > fuzz)"
// // + " gl_FragColor = u_color;"
// // + " else if (len < min_fuzz)"
// // + " gl_FragColor = blank;"
// // + " else"
// + " gl_FragColor = u_color * smoothstep(min_fuzz, fuzz, len);"
// + " } else {"
// + " float fuzz = max(fwidth(v_st.s), fwidth(v_st.t)) * 1.5;"
// + " gl_FragColor = u_color * smoothstep(-fuzz * u_mode[0], fuzz, width - length(v_st));"
// + " } "
// + "glFragColor = color"
// + "}";
// final static String gLineFragmentShader = ""
// + "#extension GL_OES_standard_derivatives : enable\n"
// + "precision mediump float;"
// + "uniform float u_width;"
// + "uniform vec2 u_mode;"
// + "uniform vec4 u_color;"
// + "const float zero = 0.0;"
// // + "const vec4 blank = vec4(1.0, 0.0, 0.0, 1.0);"
// + "varying vec2 v_st;"
// + "void main() {"
// + "float width = u_mode[1];"
// // + "float alpha = 1.0;"
// + " if (u_mode[0] == zero) {"
// // + " gl_FragColor = u_color;"
// // + " float fuzz;"
// // + " float len;"
// + " if (v_st.t == zero){ "
// // + " fuzz = - sqrt(dFdx(v_st.s) * dFdx(v_st.s) + dFdy(v_st.s) * dFdy(v_st.s));"
// + " float fuzz = -fwidth(v_st.s) * 1.5;"
// + " float len = abs(v_st.s) - width;"
// // + " if (len < fuzz)"
// + " gl_FragColor = u_color * smoothstep(zero, fuzz, len);"
// + " } else {"
// + " float fuzz = -max(fwidth(v_st.s), fwidth(v_st.t)) * 1.5;"
// + " float len = length(v_st) - width;"
// // + " if (len < fuzz)"
// + " gl_FragColor = u_color * smoothstep(zero, fuzz, len);"
// + " } "
// // + " if (len > zero)"
// // + " gl_FragColor = blank;"
// // + " discard;"
// // + " gl_FragColor = u_color;"
// // + " else if (len < fuzz)"
// // + " gl_FragColor = blank2;"
// // + " else "
// + " } else { "
// + " float fuzz = fwidth(v_st.s);"
// // + " gl_FragColor = u_color * smoothstep(fuzz, zero, abs(v_st.s) - u_width + fuzz);"
// // + " fuzz = - sqrt(dFdx(v_st.s) * dFdx(v_st.s) + dFdy(v_st.s) * dFdy(v_st.s)) * 1.5;"
// + " gl_FragColor = u_color * smoothstep(fuzz*0.5, -fuzz, abs(v_st.s) - width);"
// + " }"
// + "}";
//
// final static String gLineFragmentShader = "" +
// "#extension GL_OES_standard_derivatives : enable\n" +
// "precision mediump float;" +
// "uniform int u_mode;" +
// "uniform vec4 u_color;" +
// "varying vec2 v_st;" +
// "void main() {" +
// " gl_FragColor = u_color;" +
// "}";
final static String gLineFragmentShaderSimple = ""
+ "precision mediump float;"
+ "uniform vec4 u_color;"
+ "uniform vec2 u_mode;"
+ "uniform float u_width;" + "uniform float u_width;"
+ "varying vec2 v_st;" + "uniform float u_offset;"
+ "const float dscale = 8.0/1000.0;"
+ "void main() {" + "void main() {"
+ " gl_FragColor = u_color;" + " vec2 dir = dscale * u_width * a_position.zw;"
+ " float width = u_width * u_mode[1];" + " gl_Position = mvp * vec4(a_position.xy + dir, 0.0,1.0);"
+ " v_st = u_width * a_st;"
+ "}";
// final static String lineFragmentShader = ""
// + "precision mediump float;\n"
// + "uniform float u_wscale;"
// + "uniform float u_width;"
// + "uniform vec4 u_color;"
// + "varying vec2 v_st;"
// + "const float zero = 0.0;"
// + "void main() {"
// + " vec4 color = u_color;"
// + " float len;"
// + " if (v_st.t == zero)"
// + " len = abs(v_st.s);"
// + " else "
// + " len = length(v_st);"
// + " color.a *= smoothstep(zero, u_wscale, u_width - len);"
// + " gl_FragColor = color;"
// + "}";
final static String lineFragmentShader = ""
+ "#extension GL_OES_standard_derivatives : enable\n"
+ "precision mediump float;\n"
+ "uniform float u_wscale;"
+ "uniform float u_width;"
+ "uniform vec4 u_color;"
+ "varying vec2 v_st;"
+ "const float zero = 0.0;"
+ "void main() {"
+ " vec4 color = u_color;"
+ " float width = u_width;"
+ " float len;" + " float len;"
+ " if (v_st.t == 0.0) " + " if (v_st.t == zero)"
+ " len = abs(v_st.s);" + " len = abs(v_st.s);"
+ " else " + " else "
+ " len = length(v_st);" + " len = length(v_st);"
+ " gl_FragColor.a = smoothstep(width, width - u_mode[1], width * len);" // + " if (u_width - len < 2.0){"
+ " vec2 st_width = fwidth(v_st);"
+ " float fuzz = max(st_width.s, st_width.t) * 1.5;"
+ " color.a *= smoothstep(zero, fuzz + u_wscale, u_width - len);"
// + " }"
+ " gl_FragColor = color;"
+ "}"; + "}";
final static String gPolygonVertexShader = "" final static String polygonVertexShader = ""
+ "precision mediump float; \n" + "precision mediump float;"
+ "uniform mat4 u_center;\n" + "uniform mat4 mvp;"
+ "attribute vec4 a_position;" + "attribute vec4 a_position;"
+ "const vec4 scale = vec4(1.0/16.0, 1.0/16.0, 0.0, 1.0);" + "uniform float u_offset;"
+ "void main() {" + "void main() {"
+ " gl_Position = u_center * (scale * a_position);" + " gl_Position = mvp * a_position;"
+ "}"; + "}";
final static String gPolygonFragmentShader = "" final static String polygonFragmentShader = ""
+ "precision mediump float;" + "precision mediump float;"
+ "uniform vec4 u_color;" + "uniform vec4 u_color;"
+ "void main() {" + "void main() {"
+ " gl_FragColor = u_color;" + " gl_FragColor = u_color;"
+ "}"; + "}";
final static String textVertexShader = ""
+ "precision highp float; "
+ "attribute vec4 vertex;"
+ "attribute vec2 tex_coord;"
+ "uniform mat4 mvp;"
+ "uniform float scale;"
+ "varying vec2 tex_c;"
+ "const vec2 div = vec2(1.0/4096.0,1.0/2048.0);"
+ "void main() {"
+ " gl_Position = mvp * vec4(vertex.xy + (vertex.zw / scale), 0.0, 1.0);"
+ " tex_c = tex_coord * div;"
+ "}";
final static String textFragmentShader = ""
+ "precision highp float;"
+ "uniform sampler2D tex;"
+ "uniform vec4 col;"
+ "varying vec2 tex_c;"
+ "void main() {"
+ " gl_FragColor = texture2D(tex, tex_c.xy);"
+ "}";
// final static String lineVertexZigZagShader = ""
// + "precision mediump float; \n"
// + "uniform mat4 mvp;"
// + "attribute vec4 a_pos1;"
// + "attribute vec2 a_st1;"
// + "attribute vec4 a_pos2;"
// + "attribute vec2 a_st2;"
// + "varying vec2 v_st;"
// + "uniform vec2 u_mode;"
// + "const float dscale = 1.0/1000.0;"
// + "void main() {"
// + "if (gl_VertexID & 1 == 0) {"
// + " vec2 dir = dscale * u_mode[1] * a_pos1.zw;"
// + " gl_Position = mvp * vec4(a_pos1.xy + dir, 0.0,1.0);"
// + " v_st = u_mode[1] * a_st1;"
// + "} else {"
// + " vec2 dir = dscale * u_mode[1] * a_pos2.zw;"
// + " gl_Position = mvp * vec4( a_pos1.xy, dir, 0.0,1.0);"
// + " v_st = u_mode[1] * vec2(-a_st2.s , a_st2.t);"
// + "}";
// final static String lineFragmentShader = ""
// + "#extension GL_OES_standard_derivatives : enable\n"
// + "precision mediump float;\n"
// + "uniform vec2 u_mode;"
// + "uniform vec4 u_color;"
// + "varying vec2 v_st;"
// + "const float zero = 0.0;"
// + "void main() {"
// + " vec4 color = u_color;"
// + " float width = u_mode[1];"
// + " float len;"
// + " if (v_st.t == zero)"
// + " len = abs(v_st.s);"
// + " else "
// + " len = length(v_st);"
// + " vec2 st_width = fwidth(v_st);"
// + " float fuzz = max(st_width.s, st_width.t);"
// + " color.a *= smoothstep(-pixel, fuzz*pixel, width - (len * width));"
// + " gl_FragColor = color;"
// + "}";
} }

View File

@ -24,5 +24,6 @@ public class ShortItem {
used = 0; used = 0;
} }
static int SIZE = 128; // must be multiple of 6 and 4 (expected in LineLayer/PolygonLayer)
static final int SIZE = 240;
} }

View File

@ -14,59 +14,80 @@
*/ */
package org.mapsforge.android.glrenderer; package org.mapsforge.android.glrenderer;
import android.annotation.SuppressLint; import android.util.Log;
public class ShortPool { public class ShortPool {
private static final int POOL_LIMIT = 8192; private static final int POOL_LIMIT = 6000;
@SuppressLint("UseValueOf")
private static final Boolean lock = new Boolean(true);
static private ShortItem pool = null; static private ShortItem pool = null;
static private int count = 0; static private int count = 0;
static private int countAll = 0;
static ShortItem get() { static synchronized void finish() {
synchronized (lock) { count = 0;
countAll = 0;
pool = null;
}
if (count == 0) static synchronized ShortItem get() {
if (pool == null) {
countAll++;
return new ShortItem(); return new ShortItem();
}
count--; count--;
if (count < 0) {
int c = 0;
for (ShortItem tmp = pool; tmp != null; tmp = tmp.next)
c++;
Log.d("ShortPool", "eek wrong count: " + count + " left" + c);
return new ShortItem();
}
ShortItem it = pool; ShortItem it = pool;
pool = pool.next; pool = pool.next;
it.used = 0; it.used = 0;
it.next = null; it.next = null;
return it; return it;
} }
}
static void add(ShortItem items) { static synchronized void add(ShortItem items) {
if (items == null) if (items == null)
return; return;
synchronized (lock) { // limit pool items
if (countAll < POOL_LIMIT) {
ShortItem last = items; ShortItem last = items;
// limit pool items while (true) {
while (count < POOL_LIMIT) {
if (last.next == null) {
break;
}
last = last.next;
count++; count++;
}
// clear references if (last.next == null)
ShortItem tmp2, tmp = last.next; break;
while (tmp != null) {
tmp2 = tmp; last = last.next;
tmp = tmp.next;
tmp2.next = null;
} }
last.next = pool; last.next = pool;
pool = items; pool = items;
} else {
// int cleared = 0;
ShortItem prev, tmp = items;
while (tmp != null) {
prev = tmp;
tmp = tmp.next;
countAll--;
prev.next = null;
}
} }
} }
} }

View File

@ -15,6 +15,7 @@
package org.mapsforge.android.glrenderer; package org.mapsforge.android.glrenderer;
import org.mapsforge.android.rendertheme.renderinstruction.Caption; import org.mapsforge.android.rendertheme.renderinstruction.Caption;
import org.mapsforge.android.rendertheme.renderinstruction.PathText;
public class TextItem { public class TextItem {
TextItem next; TextItem next;
@ -22,14 +23,27 @@ public class TextItem {
final float x, y; final float x, y;
final String text; final String text;
final Caption caption; final Caption caption;
final PathText path;
final float width; final float width;
short x1, y1, x2, y2;
public TextItem(float x, float y, String text, Caption caption) { public TextItem(float x, float y, String text, Caption caption) {
this.x = x; this.x = x;
this.y = y; this.y = y;
this.text = text; this.text = text;
this.caption = caption; this.caption = caption;
this.width = caption.paint.measureText(text); this.width = caption.paint.measureText(text);
this.path = null;
}
public TextItem(float x, float y, String text, PathText pathText, float width) {
this.x = x;
this.y = y;
this.text = text;
this.path = pathText;
this.caption = null;
this.width = width;
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2010, 2011, 2012 mapsforge.org * Copyright 2012 Hannes Janetzek
* *
* This program is free software: you can redistribute it and/or modify it under the * This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software * terms of the GNU Lesser General Public License as published by the Free Software
@ -26,58 +26,59 @@ import android.graphics.Color;
import android.graphics.Paint; import android.graphics.Paint;
import android.opengl.GLES20; import android.opengl.GLES20;
import android.opengl.GLUtils; import android.opengl.GLUtils;
import android.util.FloatMath;
import android.util.Log; import android.util.Log;
public class TextRenderer { public class TextRenderer {
private final static int TEXTURE_WIDTH = 512; private final static int TEXTURE_WIDTH = 512;
private final static int TEXTURE_HEIGHT = 256; private final static int TEXTURE_HEIGHT = 256;
private final static float SCALE_FACTOR = 8.0f;
final static int MAX_LABELS = 30; final static int INDICES_PER_SPRITE = 6;
final static int VERTICES_PER_SPRITE = 4;
private final Bitmap mBitmap;
private final Canvas mCanvas;
private int mFontPadX = 1;
private int mFontPadY = 1;
private int mBitmapFormat;
private int mBitmapType;
private ByteBuffer mByteBuffer;
private ShortBuffer mShortBuffer;
private TextTexture[] mTextures;
private int mIndicesVBO;
private int mVerticesVBO;
final static int INDICES_PER_SPRITE = 6; // Indices Per Sprite
final static int VERTICES_PER_SPRITE = 4; // Vertices Per Sprite
final static int SHORTS_PER_VERTICE = 6; final static int SHORTS_PER_VERTICE = 6;
final static int MAX_LABELS = 35;
private static Bitmap mBitmap;
private static Canvas mCanvas;
private static int mFontPadX = 1;
private static int mFontPadY = 1;
private static int mBitmapFormat;
private static int mBitmapType;
private static ByteBuffer mByteBuffer;
private static ShortBuffer mShortBuffer;
private static TextTexture[] mTextures;
private static int mIndicesVBO;
private static int mVerticesVBO;
private static int mTextProgram; private static int mTextProgram;
static int hTextUVPMatrix; private static int hTextUVPMatrix;
static int hTextVertex; private static int hTextVertex;
static int hTextScale; private static int hTextScale;
static int hTextTextureCoord; private static int hTextTextureCoord;
static int hTextUColor; // private static int hTextUColor;
static Paint mPaint = new Paint(Color.BLACK); static Paint mPaint = new Paint(Color.BLACK);
boolean debug = false; private static boolean debug = false;
short[] debugVertices = { private static short[] debugVertices = {
0, 0, 0, 0,
0, TEXTURE_HEIGHT, 0, TEXTURE_HEIGHT * 4,
0, TEXTURE_HEIGHT - 1, 0, TEXTURE_HEIGHT - 1,
0, 0, 0, 0,
TEXTURE_WIDTH - 1, 0, TEXTURE_WIDTH - 1, 0,
TEXTURE_WIDTH, TEXTURE_HEIGHT, TEXTURE_WIDTH * 4, TEXTURE_HEIGHT * 4,
TEXTURE_WIDTH - 1, TEXTURE_HEIGHT - 1, TEXTURE_WIDTH - 1, TEXTURE_HEIGHT - 1,
TEXTURE_WIDTH, 0, TEXTURE_WIDTH * 4, 0,
}; };
TextRenderer(int numTextures) { static boolean init(int numTextures) {
mBitmap = Bitmap mBitmap = Bitmap
.createBitmap(TEXTURE_WIDTH, TEXTURE_HEIGHT, Bitmap.Config.ARGB_8888); .createBitmap(TEXTURE_WIDTH, TEXTURE_HEIGHT, Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap); mCanvas = new Canvas(mBitmap);
@ -85,15 +86,14 @@ public class TextRenderer {
mBitmapFormat = GLUtils.getInternalFormat(mBitmap); mBitmapFormat = GLUtils.getInternalFormat(mBitmap);
mBitmapType = GLUtils.getType(mBitmap); mBitmapType = GLUtils.getType(mBitmap);
mTextProgram = GlUtils.createProgram(textVertexShader, textFragmentShader); mTextProgram = GlUtils.createProgram(Shaders.textVertexShader,
Shaders.textFragmentShader);
hTextUVPMatrix = GLES20.glGetUniformLocation(mTextProgram, "mvp"); hTextUVPMatrix = GLES20.glGetUniformLocation(mTextProgram, "mvp");
hTextUColor = GLES20.glGetUniformLocation(mTextProgram, "col");
hTextVertex = GLES20.glGetAttribLocation(mTextProgram, "vertex"); hTextVertex = GLES20.glGetAttribLocation(mTextProgram, "vertex");
hTextScale = GLES20.glGetUniformLocation(mTextProgram, "scale"); hTextScale = GLES20.glGetUniformLocation(mTextProgram, "scale");
hTextTextureCoord = GLES20.glGetAttribLocation(mTextProgram, "tex_coord"); hTextTextureCoord = GLES20.glGetAttribLocation(mTextProgram, "tex_coord");
// mVertexBuffer = new float[];
int bufferSize = numTextures int bufferSize = numTextures
* MAX_LABELS * VERTICES_PER_SPRITE * MAX_LABELS * VERTICES_PER_SPRITE
* SHORTS_PER_VERTICE * (Short.SIZE / 8); * SHORTS_PER_VERTICE * (Short.SIZE / 8);
@ -121,12 +121,12 @@ public class TextRenderer {
GLES20.GL_CLAMP_TO_EDGE); // Set V Wrapping GLES20.GL_CLAMP_TO_EDGE); // Set V Wrapping
// load the generated bitmap onto the texture // load the generated bitmap onto the texture
// GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, mBitmap, 0);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, mBitmapFormat, mBitmap, GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, mBitmapFormat, mBitmap,
mBitmapType, 0); mBitmapType, 0);
textures[i] = new TextTexture(textureIds[i]); textures[i] = new TextTexture(textureIds[i]);
} }
GlUtils.checkGlError("init textures"); GlUtils.checkGlError("init textures");
mTextures = textures; mTextures = textures;
@ -136,12 +136,18 @@ public class TextRenderer {
int len = indices.length; int len = indices.length;
short j = 0; short j = 0;
for (int i = 0; i < len; i += INDICES_PER_SPRITE, j += VERTICES_PER_SPRITE) { for (int i = 0; i < len; i += INDICES_PER_SPRITE, j += VERTICES_PER_SPRITE) {
// indices[i + 0] = (short) (j + 0);
// indices[i + 1] = (short) (j + 1);
// indices[i + 2] = (short) (j + 2);
// indices[i + 3] = (short) (j + 2);
// indices[i + 4] = (short) (j + 3);
// indices[i + 5] = (short) (j + 0);
indices[i + 0] = (short) (j + 0); indices[i + 0] = (short) (j + 0);
indices[i + 1] = (short) (j + 1); indices[i + 1] = (short) (j + 0);
indices[i + 2] = (short) (j + 2); indices[i + 2] = (short) (j + 1);
indices[i + 3] = (short) (j + 2); indices[i + 3] = (short) (j + 3);
indices[i + 4] = (short) (j + 3); indices[i + 4] = (short) (j + 2);
indices[i + 5] = (short) (j + 0); indices[i + 5] = (short) (j + 2);
} }
ShortBuffer tmpIndices = mByteBuffer.asShortBuffer(); ShortBuffer tmpIndices = mByteBuffer.asShortBuffer();
@ -151,21 +157,25 @@ public class TextRenderer {
int[] mVboIds = new int[2]; int[] mVboIds = new int[2];
GLES20.glGenBuffers(2, mVboIds, 0); GLES20.glGenBuffers(2, mVboIds, 0);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, mVboIds[0]);
GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER, len * (Short.SIZE / 8),
tmpIndices,
GLES20.GL_STATIC_DRAW);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
mIndicesVBO = mVboIds[0]; mIndicesVBO = mVboIds[0];
mVerticesVBO = mVboIds[1]; mVerticesVBO = mVboIds[1];
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, mIndicesVBO);
GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER, len * (Short.SIZE / 8),
tmpIndices, GLES20.GL_STATIC_DRAW);
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mVerticesVBO);
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, bufferSize,
mShortBuffer, GLES20.GL_DYNAMIC_DRAW);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
return true;
} }
boolean drawToTexture(GLMapTile tile) { static boolean drawToTexture(GLMapTile tile) {
TextTexture tex = null; TextTexture tex = null;
if (tile.labels.size() == 0) if (tile.labels == null)
return false; return false;
for (int i = 0; i < mTextures.length; i++) { for (int i = 0; i < mTextures.length; i++) {
@ -194,9 +204,7 @@ public class TextRenderer {
float x = mFontPadX; float x = mFontPadX;
float width, height; float width, height;
int max = tile.labels.size(); int max = MAX_LABELS;
if (max > MAX_LABELS)
max = MAX_LABELS;
if (debug) { if (debug) {
mCanvas.drawLine(debugVertices[0], debugVertices[1], debugVertices[4], mCanvas.drawLine(debugVertices[0], debugVertices[1], debugVertices[4],
@ -212,10 +220,18 @@ public class TextRenderer {
int advanceY = 0; int advanceY = 0;
for (int i = 0; i < max; i++) { TextItem t = tile.labels;
TextItem t = tile.labels.get(i); float yy;
short x1, x2, x3, x4, y1, y2, y3, y4;
for (int i = 0; t != null && i < max; t = t.next, i++) {
if (t.caption != null) {
height = (int) (t.caption.fontHeight) + 2 * mFontPadY; height = (int) (t.caption.fontHeight) + 2 * mFontPadY;
} else {
height = (int) (t.path.fontHeight) + 2 * mFontPadY;
}
width = t.width + 2 * mFontPadX; width = t.width + 2 * mFontPadX;
if (height > advanceY) if (height > advanceY)
@ -227,45 +243,71 @@ public class TextRenderer {
advanceY = (int) height; advanceY = (int) height;
} }
float yy = y + (height - 1) - t.caption.fontDescent - mFontPadY; if (t.caption != null) {
yy = y + (height - 1) - t.caption.fontDescent - mFontPadY;
} else {
yy = y + (height - 1) - t.path.fontDescent - mFontPadY;
}
if (yy > TEXTURE_HEIGHT) { if (yy > TEXTURE_HEIGHT) {
Log.d(TAG, "reached max labels"); Log.d(TAG, "reached max labels");
continue; continue;
} }
if (t.caption != null) {
if (t.caption.stroke != null) if (t.caption.stroke != null)
mCanvas.drawText(t.text, x + t.width / 2, yy, t.caption.stroke); mCanvas.drawText(t.text, x + t.width / 2, yy, t.caption.stroke);
mCanvas.drawText(t.text, x + t.width / 2, yy, t.caption.paint); mCanvas.drawText(t.text, x + t.width / 2, yy, t.caption.paint);
} else {
if (t.path.stroke != null)
mCanvas.drawText(t.text, x + t.width / 2, yy, t.path.stroke);
// Log.d(TAG, "draw: " + t.text + " at:" + (xx + t.width / 2) + " " + yy + " w:" mCanvas.drawText(t.text, x + t.width / 2, yy, t.path.paint);
// + t.width + " " + cellHeight); }
if (width > TEXTURE_WIDTH) if (width > TEXTURE_WIDTH)
width = TEXTURE_WIDTH; width = TEXTURE_WIDTH;
float halfWidth = width / 2.0f; float hw = width / 2.0f;
float halfHeight = height / 2.0f; float hh = height / 2.0f;
// short x1 = (short) (2.0f * (t.x - halfWidth)); if (t.caption != null) {
// short y1 = (short) (2.0f * (t.y - halfHeight)); x1 = x3 = (short) (SCALE_FACTOR * (-hw));
// short x2 = (short) (2.0f * (t.x + halfWidth)); y1 = y3 = (short) (SCALE_FACTOR * (-hh));
// short y2 = (short) (2.0f * (t.y + halfHeight)); x2 = x4 = (short) (SCALE_FACTOR * (hw));
y2 = y4 = (short) (SCALE_FACTOR * (hh));
}
else {
float vx = t.x1 - t.x2;
float vy = t.y1 - t.y2;
float a = FloatMath.sqrt(vx * vx + vy * vy);
vx = vx / a;
vy = vy / a;
short x1 = (short) (2.0f * (-halfWidth)); float ux = -vy;
short y1 = (short) (2.0f * (-halfHeight)); float uy = vx;
short x2 = (short) (2.0f * (halfWidth));
short y2 = (short) (2.0f * (halfHeight));
short u1 = (short) (2.0f * x); x1 = (short) (SCALE_FACTOR * (vx * hw + ux * hh));
short v1 = (short) (2.0f * y); y1 = (short) (SCALE_FACTOR * (vy * hw + uy * hh));
short u2 = (short) (2.0f * (x + width));
short v2 = (short) (2.0f * (y + height));
short tx = (short) (2.0f * t.x); x2 = (short) (SCALE_FACTOR * (-vx * hw + ux * hh));
short ty = (short) (2.0f * t.y); y3 = (short) (SCALE_FACTOR * (-vy * hw + uy * hh));
x4 = (short) (SCALE_FACTOR * (-vx * hw - ux * hh));
y4 = (short) (SCALE_FACTOR * (-vy * hw - uy * hh));
x3 = (short) (SCALE_FACTOR * (vx * hw - ux * hh));
y2 = (short) (SCALE_FACTOR * (vy * hw - uy * hh));
}
short u1 = (short) (SCALE_FACTOR * x);
short v1 = (short) (SCALE_FACTOR * y);
short u2 = (short) (SCALE_FACTOR * (x + width));
short v2 = (short) (SCALE_FACTOR * (y + height));
short tx = (short) (SCALE_FACTOR * t.x);
short ty = (short) (SCALE_FACTOR * t.y);
// top-left
buf[pos++] = tx; buf[pos++] = tx;
buf[pos++] = ty; buf[pos++] = ty;
buf[pos++] = x1; buf[pos++] = x1;
@ -273,23 +315,26 @@ public class TextRenderer {
buf[pos++] = u1; buf[pos++] = u1;
buf[pos++] = v2; buf[pos++] = v2;
// top-right
buf[pos++] = tx; buf[pos++] = tx;
buf[pos++] = ty; buf[pos++] = ty;
buf[pos++] = x2; buf[pos++] = x2;
buf[pos++] = y1; buf[pos++] = y3;
buf[pos++] = u2; buf[pos++] = u2;
buf[pos++] = v2; buf[pos++] = v2;
// bot-right
buf[pos++] = tx; buf[pos++] = tx;
buf[pos++] = ty; buf[pos++] = ty;
buf[pos++] = x2; buf[pos++] = x4;
buf[pos++] = y2; buf[pos++] = y4;
buf[pos++] = u2; buf[pos++] = u2;
buf[pos++] = v1; buf[pos++] = v1;
// bot-left
buf[pos++] = tx; buf[pos++] = tx;
buf[pos++] = ty; buf[pos++] = ty;
buf[pos++] = x1; buf[pos++] = x3;
buf[pos++] = y2; buf[pos++] = y2;
buf[pos++] = u1; buf[pos++] = u1;
buf[pos++] = v1; buf[pos++] = v1;
@ -305,19 +350,16 @@ public class TextRenderer {
tex.length = pos; tex.length = pos;
tile.texture = tex; tile.texture = tex;
tex.tile = tile; tex.tile = tile;
// GlUtils.checkGlError("0");
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, tex.id); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, tex.id);
// GlUtils.checkGlError("1"); GLUtils.texSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, mBitmap,
GLUtils.texSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, mBitmap, mBitmapFormat, mBitmapFormat, mBitmapType);
mBitmapType);
// GlUtils.checkGlError("2");
return true; return true;
} }
private static String TAG = "TextRenderer"; private static String TAG = "TextRenderer";
void compileTextures() { static void compileTextures() {
int offset = 0; int offset = 0;
TextTexture tex; TextTexture tex;
@ -339,16 +381,18 @@ public class TextRenderer {
// Log.d(TAG, "compileTextures" + mFloatBuffer.remaining() + " " + offset); // Log.d(TAG, "compileTextures" + mFloatBuffer.remaining() + " " + offset);
// TODO use sub-bufferdata function // TODO use sub-bufferdata function
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, offset * (Short.SIZE / 8), GLES20.glBufferSubData(GLES20.GL_ARRAY_BUFFER, 0, offset * (Short.SIZE / 8),
mShortBuffer, GLES20.GL_DYNAMIC_DRAW); mShortBuffer);
} }
void beginDraw(float scale) { static void beginDraw(float scale) {
GLES20.glUseProgram(mTextProgram); GLES20.glUseProgram(mTextProgram);
GLES20.glEnableVertexAttribArray(hTextTextureCoord); GLES20.glEnableVertexAttribArray(hTextTextureCoord);
GLES20.glEnableVertexAttribArray(hTextVertex); GLES20.glEnableVertexAttribArray(hTextVertex);
GLES20.glUniform1f(hTextScale, scale); GLES20.glUniform1f(hTextScale, scale);
if (debug) { if (debug) {
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0); GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
mShortBuffer.clear(); mShortBuffer.clear();
@ -365,13 +409,13 @@ public class TextRenderer {
} }
} }
void endDraw() { static void endDraw() {
GLES20.glDisableVertexAttribArray(hTextTextureCoord); GLES20.glDisableVertexAttribArray(hTextTextureCoord);
GLES20.glDisableVertexAttribArray(hTextVertex); GLES20.glDisableVertexAttribArray(hTextVertex);
} }
void drawTile(GLMapTile tile, float[] matrix) { static void drawTile(GLMapTile tile, float[] matrix) {
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, tile.texture.id); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, tile.texture.id);
@ -384,43 +428,12 @@ public class TextRenderer {
GLES20.glVertexAttribPointer(hTextVertex, 4, GLES20.glVertexAttribPointer(hTextVertex, 4,
GLES20.GL_SHORT, false, 12, tile.texture.offset * (Short.SIZE / 8)); GLES20.GL_SHORT, false, 12, tile.texture.offset * (Short.SIZE / 8));
// GLES20.glVertexAttribPointer(hTextVertexOffset, 2,
// GLES20.GL_SHORT, false, 8, tile.texture.offset * (Short.SIZE / 8) + 4);
//
GLES20.glVertexAttribPointer(hTextTextureCoord, 2, GLES20.glVertexAttribPointer(hTextTextureCoord, 2,
GLES20.GL_SHORT, false, 12, tile.texture.offset * (Short.SIZE / 8) GLES20.GL_SHORT, false, 12, tile.texture.offset * (Short.SIZE / 8)
+ 8); + 8);
GLES20.glDrawElements(GLES20.GL_TRIANGLES, (tile.texture.length / 24) * GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP, (tile.texture.length / 24) *
INDICES_PER_SPRITE, GLES20.GL_UNSIGNED_SHORT, 0); INDICES_PER_SPRITE, GLES20.GL_UNSIGNED_SHORT, 0);
} }
} }
private static String textVertexShader = ""
+ "precision highp float; "
+ "attribute vec4 vertex;"
// + "attribute vec4 offset;"
+ "attribute vec2 tex_coord;"
+ "uniform mat4 mvp;"
+ "uniform float scale;"
+ "varying vec2 tex_c;"
+ "const vec2 div = vec2(1.0/1024.0,1.0/512.0);"
+ "const vec4 dp = vec4(0.5,0.5,0.5,0.5);"
+ "void main() {"
+ " vec4 s = dp * vertex;"
+ " gl_Position = mvp * vec4(s.x + (s.z / scale), s.y + (s.w / scale), 0.0, 1.0);"
// + " gl_Position = vec4(pos.x + s.z, pos.y + s.w, 0.0, 1.0);"
+ " tex_c = tex_coord * div;"
+ "}";
private static String textFragmentShader = ""
+ "precision highp float;"
+ "uniform sampler2D tex;"
+ "uniform vec4 col;"
+ "varying vec2 tex_c;"
+ "void main() {"
+ " gl_FragColor = texture2D(tex, tex_c.xy);"
+ "}";
} }

View File

@ -0,0 +1,285 @@
/*
* Copyright 2010, 2011, 2012 mapsforge.org
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mapsforge.android.glrenderer;
import org.mapsforge.android.rendertheme.renderinstruction.PathText;
import org.mapsforge.android.utils.GeometryUtils;
import android.util.FloatMath;
final class WayDecorator {
// /**
// * Minimum distance in pixels before the symbol is repeated.
// */
// private static final int DISTANCE_BETWEEN_SYMBOLS = 200;
/**
* Minimum distance in pixels before the way name is repeated.
*/
private static final int DISTANCE_BETWEEN_WAY_NAMES = 500;
// /**
// * Distance in pixels to skip from both ends of a segment.
// */
// private static final int SEGMENT_SAFETY_DISTANCE = 30;
// static void renderSymbol(Bitmap symbolBitmap, boolean alignCenter,
// boolean repeatSymbol, float[][] coordinates,
// List<SymbolContainer> waySymbols) {
// int skipPixels = SEGMENT_SAFETY_DISTANCE;
//
// // get the first way point coordinates
// float previousX = coordinates[0][0];
// float previousY = coordinates[0][1];
//
// // draw the symbol on each way segment
// float segmentLengthRemaining;
// float segmentSkipPercentage;
// float symbolAngle;
// for (int i = 2; i < coordinates[0].length; i += 2) {
// // get the current way point coordinates
// float currentX = coordinates[0][i];
// float currentY = coordinates[0][i + 1];
//
// // calculate the length of the current segment (Euclidian distance)
// float diffX = currentX - previousX;
// float diffY = currentY - previousY;
// double segmentLengthInPixel = Math.sqrt(diffX * diffX + diffY * diffY);
// segmentLengthRemaining = (float) segmentLengthInPixel;
//
// while (segmentLengthRemaining - skipPixels > SEGMENT_SAFETY_DISTANCE) {
// // calculate the percentage of the current segment to skip
// segmentSkipPercentage = skipPixels / segmentLengthRemaining;
//
// // move the previous point forward towards the current point
// previousX += diffX * segmentSkipPercentage;
// previousY += diffY * segmentSkipPercentage;
// symbolAngle = (float) Math.toDegrees(Math.atan2(currentY - previousY,
// currentX - previousX));
//
// waySymbols.add(new SymbolContainer(symbolBitmap, previousX, previousY,
// alignCenter, symbolAngle));
//
// // check if the symbol should only be rendered once
// if (!repeatSymbol) {
// return;
// }
//
// // recalculate the distances
// diffX = currentX - previousX;
// diffY = currentY - previousY;
//
// // recalculate the remaining length of the current segment
// segmentLengthRemaining -= skipPixels;
//
// // set the amount of pixels to skip before repeating the symbol
// skipPixels = DISTANCE_BETWEEN_SYMBOLS;
// }
//
// skipPixels -= segmentLengthRemaining;
// if (skipPixels < SEGMENT_SAFETY_DISTANCE) {
// skipPixels = SEGMENT_SAFETY_DISTANCE;
// }
//
// // set the previous way point coordinates for the next loop
// previousX = currentX;
// previousY = currentY;
// }
// }
static TextItem renderText(float[] coordinates, String text, PathText pathText,
int pos, int len, TextItem textItems) {
TextItem items = textItems;
TextItem t = null;
// calculate the way name length plus some margin of safety
float wayNameWidth = -1;
float minWidth = 100;
int skipPixels = 0;
// get the first way point coordinates
int previousX = (int) coordinates[pos + 0];
int previousY = (int) coordinates[pos + 1];
// find way segments long enough to draw the way name on them
for (int i = pos + 2; i < pos + len; i += 2) {
// get the current way point coordinates
int currentX = (int) coordinates[i];
int currentY = (int) coordinates[i + 1];
// calculate the length of the current segment (Euclidian distance)
float diffX = currentX - previousX;
float diffY = currentY - previousY;
for (int j = i + 2; j < pos + len; j += 2) {
int nextX = (int) coordinates[j];
int nextY = (int) coordinates[j + 1];
if (diffY == 0) {
if ((currentY - nextY) != 0)
break;
currentX = nextX;
currentY = nextY;
continue;
} 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;
}
if (wayNameWidth > 0 && diffX + diffY < wayNameWidth) {
previousX = currentX;
previousY = currentY;
continue;
}
float segmentLengthInPixel = FloatMath.sqrt(diffX * diffX + diffY * diffY);
if (skipPixels > 0) {
skipPixels -= segmentLengthInPixel;
} else if (segmentLengthInPixel > minWidth) {
if (wayNameWidth < 0) {
wayNameWidth = pathText.paint.measureText(text);
}
if (segmentLengthInPixel > wayNameWidth + 25) {
float s = (wayNameWidth + 25) / segmentLengthInPixel;
int width, height;
int x1, y1, x2, y2;
if (previousX < currentX) {
x1 = previousX;
y1 = previousY;
x2 = currentX;
y2 = currentY;
} else {
x1 = currentX;
y1 = currentY;
x2 = previousX;
y2 = previousY;
}
// estimate position of text on path
width = (x2 - x1) / 2;
x2 = x2 - (int) (width - s * width);
x1 = x1 + (int) (width - s * width);
height = (y2 - y1) / 2;
y2 = y2 - (int) (height - s * height);
y1 = y1 + (int) (height - s * height);
short top = (short) (y1 < y2 ? y1 : y2);
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.text.equals(text)) {
intersects = true;
break;
}
}
}
if (intersects) {
previousX = (int) coordinates[pos + i];
previousY = (int) coordinates[pos + i + 1];
continue;
}
// Log.d("mapsforge", "add " + text + " " + first + " " + last);
if (previousX < currentX) {
x1 = previousX;
y1 = previousY;
x2 = currentX;
y2 = currentY;
} else {
x1 = currentX;
y1 = currentY;
x2 = previousX;
y2 = previousY;
}
// if (t == null)
t = new TextItem(x1 + (x2 - x1) / 2, y1 + (y2 - y1) / 2, text,
pathText, wayNameWidth);
t.x1 = (short) x1;
t.y1 = (short) y1;
t.x2 = (short) x2;
t.y2 = (short) y2;
t.next = items;
items = t;
// skipPixels = DISTANCE_BETWEEN_WAY_NAMES;
return items;
}
}
// store the previous way point coordinates
previousX = currentX;
previousY = currentY;
}
return items;
}
private WayDecorator() {
throw new IllegalStateException();
}
}

View File

@ -19,14 +19,12 @@ import org.mapsforge.core.Tile;
import android.content.Context; import android.content.Context;
import android.os.CountDownTimer; import android.os.CountDownTimer;
import android.os.SystemClock;
import android.util.Log; import android.util.Log;
import android.view.GestureDetector; import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener; import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent; import android.view.MotionEvent;
import android.view.ScaleGestureDetector; import android.view.ScaleGestureDetector;
import android.view.ViewConfiguration; import android.view.ViewConfiguration;
import android.view.animation.DecelerateInterpolator;
import android.widget.Scroller; import android.widget.Scroller;
/** /**
@ -220,27 +218,15 @@ public class TouchHandler {
} }
// if (ret) { // if (ret) {
// Log.d("", "" + ); // // throttle input
// // long diff = SystemClock.uptimeMillis() - lastRun;
// // try { // if (diff < 16 && diff > 5) {
// // // // Log.d("", "" + diff);
// // Thread.sleep(10); // SystemClock.sleep(16 - diff);
// // } catch (InterruptedException e) {
// // // TODO Auto-generated catch block
// // // e.printStackTrace();
// // }
//
// } // }
if (ret) { // lastRun = SystemClock.uptimeMillis();
// throttle input // }
long diff = SystemClock.uptimeMillis() - lastRun;
if (diff < 16) {
// Log.d("", "" + diff);
SystemClock.sleep(16 - diff);
}
lastRun = SystemClock.uptimeMillis();
}
// the event was not handled
return ret; return ret;
} }
@ -250,7 +236,8 @@ public class TouchHandler {
private CountDownTimer mTimer = null; private CountDownTimer mTimer = null;
public MapGestureDetector(MapView mapView) { public MapGestureDetector(MapView mapView) {
mScroller = new Scroller(mapView.getContext(), new DecelerateInterpolator()); mScroller = new Scroller(mapView.getContext(),
new android.view.animation.LinearInterpolator());
} }
@Override @Override
@ -284,8 +271,8 @@ public class TouchHandler {
@Override @Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) { float velocityY) {
int w = Tile.TILE_SIZE * 20; int w = Tile.TILE_SIZE * 10;
int h = Tile.TILE_SIZE * 20; int h = Tile.TILE_SIZE * 10;
mPrevX = 0; mPrevX = 0;
mPrevY = 0; mPrevY = 0;
@ -297,7 +284,7 @@ public class TouchHandler {
mScroller.fling(0, 0, Math.round(velocityX) / 2, Math.round(velocityY) / 2, mScroller.fling(0, 0, Math.round(velocityX) / 2, Math.round(velocityY) / 2,
-w, w, -h, h); -w, w, -h, h);
// animate for two seconds // animate for two seconds
mTimer = new CountDownTimer(2000, 20) { mTimer = new CountDownTimer(2000, 40) {
@Override @Override
public void onTick(long tick) { public void onTick(long tick) {
if (!scroll()) if (!scroll())

View File

@ -46,14 +46,14 @@ public class JobQueue {
* @param mapGeneratorJob * @param mapGeneratorJob
* the job to be added to this queue. * the job to be added to this queue.
*/ */
public synchronized void addJob(MapGeneratorJob mapGeneratorJob) { // public synchronized void addJob(MapGeneratorJob mapGeneratorJob) {
if (!mPriorityQueue.contains(mapGeneratorJob)) // if (!mPriorityQueue.contains(mapGeneratorJob))
// priorityQueue.remove(mapGeneratorJob); // // priorityQueue.remove(mapGeneratorJob);
{ // {
mapGeneratorJob.tile.isLoading = true; // //mapGeneratorJob.tile.isLoading = true;
mPriorityQueue.offer(mapGeneratorJob); // mPriorityQueue.offer(mapGeneratorJob);
} // }
} // }
/** /**
* @param jobs * @param jobs

View File

@ -43,7 +43,7 @@ public class MapTile extends Tile {
/** /**
* distance from center, used in TileScheduler set by updateVisibleList. * distance from center, used in TileScheduler set by updateVisibleList.
*/ */
public long distance; public float distance;
/** /**
* @param tileX * @param tileX

View File

@ -86,7 +86,7 @@ public class MapWorker extends PausableThread {
@Override @Override
protected int getThreadPriority() { protected int getThreadPriority() {
return (Thread.NORM_PRIORITY + Thread.MIN_PRIORITY) / 2; return (Thread.NORM_PRIORITY + Thread.MIN_PRIORITY) / 3;
// return mPrio; // return mPrio;
} }

View File

@ -17,6 +17,7 @@ package org.mapsforge.android.rendertheme;
import org.mapsforge.android.rendertheme.renderinstruction.Area; import org.mapsforge.android.rendertheme.renderinstruction.Area;
import org.mapsforge.android.rendertheme.renderinstruction.Caption; import org.mapsforge.android.rendertheme.renderinstruction.Caption;
import org.mapsforge.android.rendertheme.renderinstruction.Line; import org.mapsforge.android.rendertheme.renderinstruction.Line;
import org.mapsforge.android.rendertheme.renderinstruction.PathText;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Paint; import android.graphics.Paint;
@ -31,7 +32,7 @@ public interface IRenderCallback {
* @param area * @param area
* ... * ...
*/ */
void renderArea(Area area); void renderArea(Area area, int level);
/** /**
* Renders an area caption with the given text. * Renders an area caption with the given text.
@ -83,7 +84,7 @@ public interface IRenderCallback {
* @param line * @param line
* ... * ...
*/ */
void renderWay(Line line); void renderWay(Line line, int level);
/** /**
* Renders a way with the given symbol along the way path. * Renders a way with the given symbol along the way path.
@ -100,12 +101,8 @@ public interface IRenderCallback {
/** /**
* Renders a way with the given text along the way path. * Renders a way with the given text along the way path.
* *
* @param text * @param pathText
* the text to be rendered. * ...
* @param paint
* the paint to be used for rendering the text.
* @param stroke
* an optional paint for the text casing (may be null).
*/ */
void renderWayText(String text, Paint paint, Paint stroke); void renderWayText(PathText pathText);
} }

View File

@ -21,8 +21,9 @@ import org.mapsforge.core.Tag;
class NegativeMatcher implements AttributeMatcher { class NegativeMatcher implements AttributeMatcher {
private final String[] mKeyList; private final String[] mKeyList;
private final String[] mValueList; private final String[] mValueList;
private final boolean mExclusive;
NegativeMatcher(List<String> keyList, List<String> valueList) { NegativeMatcher(List<String> keyList, List<String> valueList, boolean exclusive) {
mKeyList = new String[keyList.size()]; mKeyList = new String[keyList.size()];
for (int i = 0; i < mKeyList.length; i++) for (int i = 0; i < mKeyList.length; i++)
mKeyList[i] = keyList.get(i).intern(); mKeyList[i] = keyList.get(i).intern();
@ -30,6 +31,8 @@ class NegativeMatcher implements AttributeMatcher {
mValueList = new String[valueList.size()]; mValueList = new String[valueList.size()];
for (int i = 0; i < mValueList.length; i++) for (int i = 0; i < mValueList.length; i++)
mValueList[i] = valueList.get(i).intern(); mValueList[i] = valueList.get(i).intern();
mExclusive = exclusive;
} }
@Override @Override
@ -46,9 +49,9 @@ class NegativeMatcher implements AttributeMatcher {
for (Tag tag : tags) { for (Tag tag : tags) {
for (String value : mValueList) for (String value : mValueList)
if (value == tag.value) if (value == tag.value)
return true; return !mExclusive;
} }
return false; return mExclusive;
} }
private boolean keyListDoesNotContainKeys(Tag[] tags) { private boolean keyListDoesNotContainKeys(Tag[] tags) {

View File

@ -29,14 +29,14 @@ class NegativeRule extends Rule {
@Override @Override
boolean matchesNode(Tag[] tags, byte zoomLevel) { boolean matchesNode(Tag[] tags, byte zoomLevel) {
return mZoomMin <= zoomLevel && mZoomMax >= zoomLevel return mZoomMin <= zoomLevel && mZoomMax >= zoomLevel
&& (mElement == Element.NODE || mElement == Element.ANY) && (mElement != Element.WAY)
&& mAttributeMatcher.matches(tags); && mAttributeMatcher.matches(tags);
} }
@Override @Override
boolean matchesWay(Tag[] tags, byte zoomLevel, int closed) { boolean matchesWay(Tag[] tags, byte zoomLevel, int closed) {
return mZoomMin <= zoomLevel && mZoomMax >= zoomLevel return mZoomMin <= zoomLevel && mZoomMax >= zoomLevel
&& (mElement == Element.WAY || mElement == Element.ANY) && (mElement != Element.NODE)
&& (mClosed == closed || mClosed == Closed.ANY) && (mClosed == closed || mClosed == Closed.ANY)
&& mAttributeMatcher.matches(tags); && mAttributeMatcher.matches(tags);
} }

View File

@ -37,16 +37,16 @@ class PositiveRule extends Rule {
@Override @Override
boolean matchesNode(Tag[] tags, byte zoomLevel) { boolean matchesNode(Tag[] tags, byte zoomLevel) {
return mZoomMin <= zoomLevel && mZoomMax >= zoomLevel return (mElement != Element.WAY)
&& (mElement == Element.NODE || mElement == Element.ANY) && mZoomMin <= zoomLevel && mZoomMax >= zoomLevel
&& (mKeyMatcher == null || mKeyMatcher.matches(tags)) && (mKeyMatcher == null || mKeyMatcher.matches(tags))
&& (mValueMatcher == null || mValueMatcher.matches(tags)); && (mValueMatcher == null || mValueMatcher.matches(tags));
} }
@Override @Override
boolean matchesWay(Tag[] tags, byte zoomLevel, int closed) { boolean matchesWay(Tag[] tags, byte zoomLevel, int closed) {
return mZoomMin <= zoomLevel && mZoomMax >= zoomLevel return (mElement != Element.NODE)
&& (mElement == Element.WAY || mElement == Element.ANY) && mZoomMin <= zoomLevel && mZoomMax >= zoomLevel
&& (mClosed == closed || mClosed == Closed.ANY) && (mClosed == closed || mClosed == Closed.ANY)
&& (mKeyMatcher == null || mKeyMatcher.matches(tags)) && (mKeyMatcher == null || mKeyMatcher.matches(tags))
&& (mValueMatcher == null || mValueMatcher.matches(tags)); && (mValueMatcher == null || mValueMatcher.matches(tags));

View File

@ -17,7 +17,6 @@ package org.mapsforge.android.rendertheme;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.mapsforge.android.rendertheme.renderinstruction.Line;
import org.mapsforge.android.rendertheme.renderinstruction.RenderInstruction; import org.mapsforge.android.rendertheme.renderinstruction.RenderInstruction;
import org.mapsforge.core.LRUCache; import org.mapsforge.core.LRUCache;
import org.mapsforge.core.Tag; import org.mapsforge.core.Tag;
@ -136,40 +135,112 @@ public class RenderTheme {
* ... * ...
* @param zoomLevel * @param zoomLevel
* ... * ...
* @return ...
*/ */
public void matchNode(IRenderCallback renderCallback, Tag[] tags, byte zoomLevel) { public synchronized RenderInstruction[] matchNode(IRenderCallback renderCallback,
// List<RenderInstruction> matchingList = matchingListNode; Tag[] tags,
// MatchingCacheKey matchingCacheKey = matchingCacheKeyNode; byte zoomLevel) {
// if (!changed) { RenderInstruction[] renderInstructions = null;
// if (matchingList != null) {
// for (int i = 0, n = matchingList.size(); i < n; ++i) {
// matchingList.get(i).renderNode(renderCallback, tags);
// }
// }
// return;
// }
// matchingCacheKey = new MatchingCacheKey(tags, zoomLevel);
// matchingList = matchingCacheNodes.get(matchingCacheKey);
//
// if (matchingList != null) {
// // cache hit
// for (int i = 0, n = matchingList.size(); i < n; ++i) {
// matchingList.get(i).renderNode(renderCallback, tags);
// }
// } else {
MatchingCacheKey matchingCacheKey;
matchingCacheKey = new MatchingCacheKey(tags, zoomLevel);
boolean found = mMatchingCacheNodes.containsKey(matchingCacheKey);
if (found) {
renderInstructions = mMatchingCacheNodes.get(matchingCacheKey);
} else {
// cache miss // cache miss
// matchingList = new ArrayList<RenderInstruction>(); List<RenderInstruction> matchingList = new ArrayList<RenderInstruction>(4);
for (int i = 0, n = mRulesList.size(); i < n; ++i) { for (int i = 0, n = mRulesList.size(); i < n; ++i)
mRulesList.get(i).matchNode(renderCallback, tags, zoomLevel); mRulesList.get(i)
// , matchingList .matchNode(renderCallback, tags, zoomLevel, matchingList);
int size = matchingList.size();
if (size > 0) {
renderInstructions = new RenderInstruction[size];
matchingList.toArray(renderInstructions);
} }
// matchingCacheNodes.put(matchingCacheKey, matchingList); mMatchingCacheNodes.put(matchingCacheKey, renderInstructions);
// } }
//
// matchingListNode = matchingList; if (renderInstructions != null) {
// matchingCacheKeyNode = matchingCacheKey; for (int i = 0, n = renderInstructions.length; i < n; i++)
renderInstructions[i].renderNode(renderCallback, tags);
}
return renderInstructions;
}
/**
* Matches a way with the given parameters against this RenderTheme.
*
* @param renderCallback
* the callback implementation which will be executed on each match.
* @param tags
* the tags of the way.
* @param zoomLevel
* the zoom level at which the way should be matched.
* @param closed
* way is Closed
* @param render
* ...
* @return currently processed render instructions
*/
public synchronized RenderInstruction[] matchWay(IRenderCallback renderCallback,
Tag[] tags,
byte zoomLevel,
boolean closed, boolean render) {
RenderInstruction[] renderInstructions = null;
LRUCache<MatchingCacheKey, RenderInstruction[]> matchingCache;
MatchingCacheKey matchingCacheKey;
if (closed) {
matchingCache = mMatchingCacheArea;
} else {
matchingCache = mMatchingCacheWay;
}
matchingCacheKey = new MatchingCacheKey(tags, zoomLevel);
boolean found = matchingCache.containsKey(matchingCacheKey);
if (found) {
renderInstructions = matchingCache.get(matchingCacheKey);
} else {
// cache miss
int c = (closed ? Closed.YES : Closed.NO);
List<RenderInstruction> matchingList = new ArrayList<RenderInstruction>(4);
for (int i = 0, n = mRulesList.size(); i < n; ++i) {
mRulesList.get(i).matchWay(renderCallback, tags, zoomLevel, c,
matchingList);
}
int size = matchingList.size();
if (size > 0) {
renderInstructions = new RenderInstruction[size];
matchingList.toArray(renderInstructions);
}
matchingCache.put(matchingCacheKey, renderInstructions);
}
if (render && renderInstructions != null) {
for (int i = 0, n = renderInstructions.length; i < n; i++)
renderInstructions[i].renderWay(renderCallback, tags);
}
return renderInstructions;
}
void addRule(Rule rule) {
mRulesList.add(rule);
}
void complete() {
mRulesList.trimToSize();
for (int i = 0, n = mRulesList.size(); i < n; ++i) {
mRulesList.get(i).onComplete();
}
} }
/** /**
@ -196,107 +267,6 @@ public class RenderTheme {
} }
} }
// private RenderInstruction[] mRenderInstructions = null;
/**
* Matches a way with the given parameters against this RenderTheme.
*
* @param renderCallback
* the callback implementation which will be executed on each match.
* @param tags
* the tags of the way.
* @param zoomLevel
* the zoom level at which the way should be matched.
* @param closed
* way is Closed
* @param changed
* ...
* @return currently processed render instructions
*/
public synchronized RenderInstruction[] matchWay(IRenderCallback renderCallback,
Tag[] tags,
byte zoomLevel,
boolean closed, boolean render) {
RenderInstruction[] renderInstructions = null;
LRUCache<MatchingCacheKey, RenderInstruction[]> matchingCache;
MatchingCacheKey matchingCacheKey;
// if (!changed) {
// renderInstructions = mRenderInstructions;
//
// if (renderInstructions != null) {
// for (int i = 0, n = renderInstructions.length; i < n; i++)
// renderInstructions[i].renderWay(renderCallback, tags);
// }
// return;
// }
if (closed) {
matchingCache = mMatchingCacheArea;
} else {
matchingCache = mMatchingCacheWay;
}
matchingCacheKey = new MatchingCacheKey(tags, zoomLevel);
boolean found = matchingCache.containsKey(matchingCacheKey);
if (found) {
renderInstructions = matchingCache.get(matchingCacheKey);
} else {
// cache miss
int c = (closed ? Closed.YES : Closed.NO);
List<RenderInstruction> matchingList = new ArrayList<RenderInstruction>(4);
for (int i = 0, n = mRulesList.size(); i < n; ++i) {
mRulesList.get(i).matchWay(renderCallback, tags, zoomLevel, c,
matchingList);
}
int size = matchingList.size();
if (size > 0) {
renderInstructions = new RenderInstruction[matchingList.size()];
for (int i = 0, n = matchingList.size(); i < n; ++i) {
RenderInstruction renderInstruction = matchingList.get(i);
renderInstructions[i] = renderInstruction;
}
}
matchingCache.put(matchingCacheKey, renderInstructions);
}
if (render && renderInstructions != null) {
for (int i = 0, n = renderInstructions.length; i < n; i++)
renderInstructions[i].renderWay(renderCallback, tags);
}
// mRenderInstructions = renderInstructions;
return renderInstructions;
}
void addRule(Rule rule) {
mRulesList.add(rule);
}
void complete() {
mRulesList.trimToSize();
for (int i = 0, n = mRulesList.size(); i < n; ++i) {
mRulesList.get(i).onComplete();
}
}
private final ArrayList<Line> outlineLayers = new ArrayList<Line>();
void addOutlineLayer(Line line) {
outlineLayers.add(line);
}
/**
* @param layer
* ...
* @return Line (paint and level) used for outline
*/
public Line getOutline(int layer) {
return outlineLayers.get(layer);
}
void setLevels(int levels) { void setLevels(int levels) {
mLevels = levels; mLevels = levels;
} }

View File

@ -16,6 +16,7 @@ package org.mapsforge.android.rendertheme;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.HashMap;
import java.util.Stack; import java.util.Stack;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -26,9 +27,11 @@ import javax.xml.parsers.SAXParserFactory;
import org.mapsforge.android.rendertheme.renderinstruction.Area; import org.mapsforge.android.rendertheme.renderinstruction.Area;
import org.mapsforge.android.rendertheme.renderinstruction.Caption; import org.mapsforge.android.rendertheme.renderinstruction.Caption;
import org.mapsforge.android.rendertheme.renderinstruction.Circle; import org.mapsforge.android.rendertheme.renderinstruction.Circle;
import org.mapsforge.android.rendertheme.renderinstruction.AreaLevel;
import org.mapsforge.android.rendertheme.renderinstruction.Line; import org.mapsforge.android.rendertheme.renderinstruction.Line;
import org.mapsforge.android.rendertheme.renderinstruction.LineSymbol; import org.mapsforge.android.rendertheme.renderinstruction.LineSymbol;
import org.mapsforge.android.rendertheme.renderinstruction.PathText; import org.mapsforge.android.rendertheme.renderinstruction.PathText;
import org.mapsforge.android.rendertheme.renderinstruction.RenderInstruction;
import org.mapsforge.android.rendertheme.renderinstruction.Symbol; import org.mapsforge.android.rendertheme.renderinstruction.Symbol;
import org.xml.sax.Attributes; import org.xml.sax.Attributes;
import org.xml.sax.InputSource; import org.xml.sax.InputSource;
@ -41,14 +44,23 @@ import org.xml.sax.helpers.DefaultHandler;
* SAX2 handler to parse XML render theme files. * SAX2 handler to parse XML render theme files.
*/ */
public class RenderThemeHandler extends DefaultHandler { public class RenderThemeHandler extends DefaultHandler {
private static final Logger LOG = Logger.getLogger(RenderThemeHandler.class.getName()); private static final Logger LOG = Logger
.getLogger(RenderThemeHandler.class.getName());
private static enum Element { private static enum Element {
RENDER_THEME, RENDERING_INSTRUCTION, RULE; RENDER_THEME, RENDERING_INSTRUCTION, RULE, STYLE;
} }
private static final String ELEMENT_NAME_RENDER_THEME = "rendertheme"; private static final String ELEMENT_NAME_RENDER_THEME = "rendertheme";
private static final String ELEMENT_NAME_RULE = "rule"; private static final String ELEMENT_NAME_RULE = "rule";
private static final String ELEMENT_NAME_STYPE_PATH_TEXT = "style-pathtext";
private static final String ELEMENT_NAME_STYLE_AREA = "style-area";
private static final String ELEMENT_NAME_STYLE_LINE = "style-line";
private static final String ELEMENT_NAME_STYLE_OUTLINE = "style-outline";
private static final String ELEMENT_NAME_USE_STYLE_PATH_TEXT = "use-text";
private static final String ELEMENT_NAME_USE_STYLE_AREA = "use-area";
private static final String ELEMENT_NAME_USE_STYLE_LINE = "use-line";
private static final String ELEMENT_NAME_USE_STYLE_OUTLINE = "use-outline";
private static final String UNEXPECTED_ELEMENT = "unexpected element: "; private static final String UNEXPECTED_ELEMENT = "unexpected element: ";
/** /**
@ -62,10 +74,12 @@ public class RenderThemeHandler extends DefaultHandler {
* @throws IOException * @throws IOException
* if an I/O error occurs while reading from the input stream. * if an I/O error occurs while reading from the input stream.
*/ */
public static RenderTheme getRenderTheme(InputStream inputStream) throws SAXException, public static RenderTheme getRenderTheme(InputStream inputStream)
throws SAXException,
ParserConfigurationException, IOException { ParserConfigurationException, IOException {
RenderThemeHandler renderThemeHandler = new RenderThemeHandler(); RenderThemeHandler renderThemeHandler = new RenderThemeHandler();
XMLReader xmlReader = SAXParserFactory.newInstance().newSAXParser().getXMLReader(); XMLReader xmlReader = SAXParserFactory.newInstance().newSAXParser()
.getXMLReader();
xmlReader.setContentHandler(renderThemeHandler); xmlReader.setContentHandler(renderThemeHandler);
xmlReader.parse(new InputSource(inputStream)); xmlReader.parse(new InputSource(inputStream));
return renderThemeHandler.mRenderTheme; return renderThemeHandler.mRenderTheme;
@ -83,7 +97,8 @@ public class RenderThemeHandler extends DefaultHandler {
* @param attributeIndex * @param attributeIndex
* the XML attribute index position. * the XML attribute index position.
*/ */
public static void logUnknownAttribute(String element, String name, String value, int attributeIndex) { public static void logUnknownAttribute(String element, String name, String value,
int attributeIndex) {
StringBuilder stringBuilder = new StringBuilder(); StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("unknown attribute in element "); stringBuilder.append("unknown attribute in element ");
stringBuilder.append(element); stringBuilder.append(element);
@ -110,6 +125,7 @@ public class RenderThemeHandler extends DefaultHandler {
mRenderTheme.setLevels(mLevel); mRenderTheme.setLevels(mLevel);
mRenderTheme.complete(); mRenderTheme.complete();
tmpStyleHash.clear();
} }
@Override @Override
@ -131,8 +147,12 @@ public class RenderThemeHandler extends DefaultHandler {
LOG.log(Level.SEVERE, null, exception); LOG.log(Level.SEVERE, null, exception);
} }
private static HashMap<String, RenderInstruction> tmpStyleHash = new HashMap<String, RenderInstruction>(
10);
@Override @Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { public void startElement(String uri, String localName, String qName,
Attributes attributes) throws SAXException {
try { try {
if (ELEMENT_NAME_RENDER_THEME.equals(localName)) { if (ELEMENT_NAME_RENDER_THEME.equals(localName)) {
checkState(localName, Element.RENDER_THEME); checkState(localName, Element.RENDER_THEME);
@ -149,10 +169,53 @@ public class RenderThemeHandler extends DefaultHandler {
mRuleStack.push(mCurrentRule); mRuleStack.push(mCurrentRule);
} }
else if (ELEMENT_NAME_STYPE_PATH_TEXT.equals(localName)) {
checkState(localName, Element.STYLE);
PathText pathText = PathText.create(localName, attributes);
tmpStyleHash.put("t" + pathText.style, pathText);
// System.out.println("add style: " + pathText.style);
}
else if (ELEMENT_NAME_STYLE_AREA.equals(localName)) {
checkState(localName, Element.STYLE);
Area area = Area.create(localName, attributes, 0);
tmpStyleHash.put("a" + area.style, area);
// System.out.println("add style: " + area.style);
}
else if (ELEMENT_NAME_STYLE_LINE.equals(localName)) {
checkState(localName, Element.STYLE);
String style = null;
if ((style = attributes.getValue("from")) != null) {
RenderInstruction ri = tmpStyleHash.get("l" + style);
if (ri instanceof Line) {
Line line = Line.create((Line) ri, localName, attributes, 0,
false);
tmpStyleHash.put("l" + line.style, line);
// System.out.println("add style: " + line.style + " from " + style);
}
else {
// System.out.println("couldnt check the style yo! " + style);
}
} else {
Line line = Line.create(null, localName, attributes, 0, false);
tmpStyleHash.put("l" + line.style, line);
// System.out.println("add style: " + line.style);
}
}
else if (ELEMENT_NAME_STYLE_OUTLINE.equals(localName)) {
checkState(localName, Element.RENDERING_INSTRUCTION);
Line line = Line.create(null, localName, attributes, mLevel++, true);
tmpStyleHash.put("o" + line.style, line);
// outlineLayers.add(line);
}
else if ("area".equals(localName)) { else if ("area".equals(localName)) {
checkState(localName, Element.RENDERING_INSTRUCTION); checkState(localName, Element.RENDERING_INSTRUCTION);
Area area = Area.create(localName, attributes, mLevel++); Area area = Area.create(localName, attributes, mLevel++);
mRuleStack.peek().addRenderingInstruction(area); // mRuleStack.peek().addRenderingInstruction(area);
mCurrentRule.addRenderingInstruction(area);
} }
else if ("caption".equals(localName)) { else if ("caption".equals(localName)) {
@ -169,17 +232,10 @@ public class RenderThemeHandler extends DefaultHandler {
else if ("line".equals(localName)) { else if ("line".equals(localName)) {
checkState(localName, Element.RENDERING_INSTRUCTION); checkState(localName, Element.RENDERING_INSTRUCTION);
Line line = Line.create(localName, attributes, mLevel++); Line line = Line.create(null, localName, attributes, mLevel++, false);
mCurrentRule.addRenderingInstruction(line); mCurrentRule.addRenderingInstruction(line);
} }
else if ("outline".equals(localName)) {
checkState(localName, Element.RENDERING_INSTRUCTION);
Line line = Line.create(localName, attributes, mLevel++);
mRenderTheme.addOutlineLayer(line);
// mCurrentRule.addRenderingInstruction(line);
}
else if ("lineSymbol".equals(localName)) { else if ("lineSymbol".equals(localName)) {
checkState(localName, Element.RENDERING_INSTRUCTION); checkState(localName, Element.RENDERING_INSTRUCTION);
LineSymbol lineSymbol = LineSymbol.create(localName, attributes); LineSymbol lineSymbol = LineSymbol.create(localName, attributes);
@ -198,7 +254,45 @@ public class RenderThemeHandler extends DefaultHandler {
mCurrentRule.addRenderingInstruction(symbol); mCurrentRule.addRenderingInstruction(symbol);
} }
else { else if (ELEMENT_NAME_USE_STYLE_LINE.equals(localName)) {
checkState(localName, Element.RENDERING_INSTRUCTION);
String style = attributes.getValue("name");
if (style != null) {
Line line = (Line) tmpStyleHash.get("l" + style);
if (line != null) {
// System.out.println("found style line : " + line.style);
Line newLine = Line.create(line, localName, attributes,
mLevel++, false);
mCurrentRule.addRenderingInstruction(newLine);
}
}
} else if (ELEMENT_NAME_USE_STYLE_OUTLINE.equals(localName)) {
checkState(localName, Element.RENDERING_INSTRUCTION);
String style = attributes.getValue("name");
if (style != null) {
Line line = (Line) tmpStyleHash.get("o" + style);
if (line != null && line.outline)
mCurrentRule.addRenderingInstruction(line);
}
} else if (ELEMENT_NAME_USE_STYLE_AREA.equals(localName)) {
checkState(localName, Element.RENDERING_INSTRUCTION);
String style = attributes.getValue("name");
if (style != null) {
Area area = (Area) tmpStyleHash.get("a" + style);
if (area != null)
mCurrentRule.addRenderingInstruction(new AreaLevel(area,
mLevel++));
}
} else if (ELEMENT_NAME_USE_STYLE_PATH_TEXT.equals(localName)) {
checkState(localName, Element.RENDERING_INSTRUCTION);
String style = attributes.getValue("name");
if (style != null) {
PathText pt = (PathText) tmpStyleHash.get("t" + style);
if (pt != null)
mCurrentRule.addRenderingInstruction(pt);
}
} else {
throw new SAXException("unknown element: " + localName); throw new SAXException("unknown element: " + localName);
} }
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
@ -214,6 +308,7 @@ public class RenderThemeHandler extends DefaultHandler {
} }
private void checkElement(String elementName, Element element) throws SAXException { private void checkElement(String elementName, Element element) throws SAXException {
Element parentElement;
switch (element) { switch (element) {
case RENDER_THEME: case RENDER_THEME:
if (!mElementStack.empty()) { if (!mElementStack.empty()) {
@ -222,8 +317,16 @@ public class RenderThemeHandler extends DefaultHandler {
return; return;
case RULE: case RULE:
Element parentElement = mElementStack.peek(); parentElement = mElementStack.peek();
if (parentElement != Element.RENDER_THEME && parentElement != Element.RULE) { if (parentElement != Element.RENDER_THEME
&& parentElement != Element.RULE) {
throw new SAXException(UNEXPECTED_ELEMENT + elementName);
}
return;
case STYLE:
parentElement = mElementStack.peek();
if (parentElement != Element.RENDER_THEME) {
throw new SAXException(UNEXPECTED_ELEMENT + elementName); throw new SAXException(UNEXPECTED_ELEMENT + elementName);
} }
return; return;

View File

@ -32,6 +32,7 @@ abstract class Rule {
private static final Map<List<String>, AttributeMatcher> MATCHERS_CACHE_VALUE = new HashMap<List<String>, AttributeMatcher>(); private static final Map<List<String>, AttributeMatcher> MATCHERS_CACHE_VALUE = new HashMap<List<String>, AttributeMatcher>();
private static final Pattern SPLIT_PATTERN = Pattern.compile("\\|"); private static final Pattern SPLIT_PATTERN = Pattern.compile("\\|");
private static final String STRING_NEGATION = "~"; private static final String STRING_NEGATION = "~";
private static final String STRING_EXCLUSIVE = "-";
private static final String STRING_WILDCARD = "*"; private static final String STRING_WILDCARD = "*";
private static Rule createRule(Stack<Rule> ruleStack, int element, String keys, private static Rule createRule(Stack<Rule> ruleStack, int element, String keys,
@ -44,11 +45,18 @@ abstract class Rule {
.split(values))); .split(values)));
if (valueList.remove(STRING_NEGATION)) { if (valueList.remove(STRING_NEGATION)) {
AttributeMatcher attributeMatcher = new NegativeMatcher(keyList, valueList); AttributeMatcher attributeMatcher = new NegativeMatcher(keyList, valueList,
false);
return new NegativeRule(element, closed, zoomMin, zoomMax, return new NegativeRule(element, closed, zoomMin, zoomMax,
attributeMatcher); attributeMatcher);
} }
if (valueList.remove(STRING_EXCLUSIVE)) {
AttributeMatcher attributeMatcher = new NegativeMatcher(keyList, valueList,
true);
return new NegativeRule(element, closed, zoomMin, zoomMax,
attributeMatcher);
}
AttributeMatcher keyMatcher = getKeyMatcher(keyList); AttributeMatcher keyMatcher = getKeyMatcher(keyList);
AttributeMatcher valueMatcher = getValueMatcher(valueList); AttributeMatcher valueMatcher = getValueMatcher(valueList);
@ -189,13 +197,14 @@ abstract class Rule {
abstract boolean matchesWay(Tag[] tags, byte zoomLevel, int closed); abstract boolean matchesWay(Tag[] tags, byte zoomLevel, int closed);
void matchNode(IRenderCallback renderCallback, Tag[] tags, byte zoomLevel) { void matchNode(IRenderCallback renderCallback, Tag[] tags, byte zoomLevel,
List<RenderInstruction> matchingList) {
if (matchesNode(tags, zoomLevel)) { if (matchesNode(tags, zoomLevel)) {
for (int i = 0, n = mRenderInstructionArray.length; i < n; i++) for (int i = 0, n = mRenderInstructionArray.length; i < n; i++)
mRenderInstructionArray[i].renderNode(renderCallback, tags); matchingList.add(mRenderInstructionArray[i]);
for (int i = 0, n = mSubRuleArray.length; i < n; i++) for (int i = 0, n = mSubRuleArray.length; i < n; i++)
mSubRuleArray[i].matchNode(renderCallback, tags, zoomLevel); mSubRuleArray[i].matchNode(renderCallback, tags, zoomLevel, matchingList);
} }
} }
@ -220,14 +229,15 @@ abstract class Rule {
MATCHERS_CACHE_VALUE.clear(); MATCHERS_CACHE_VALUE.clear();
mRenderInstructionArray = new RenderInstruction[mRenderInstructions.size()]; mRenderInstructionArray = new RenderInstruction[mRenderInstructions.size()];
mRenderInstructions.toArray(mRenderInstructionArray);
for (int i = 0, n = mRenderInstructions.size(); i < n; i++) // for (int i = 0, n = mRenderInstructions.size(); i < n; i++)
mRenderInstructionArray[i] = mRenderInstructions.get(i); // mRenderInstructionArray[i] = mRenderInstructions.get(i);
mSubRuleArray = new Rule[mSubRules.size()]; mSubRuleArray = new Rule[mSubRules.size()];
mSubRules.toArray(mSubRuleArray);
for (int i = 0, n = mSubRules.size(); i < n; i++) // for (int i = 0, n = mSubRules.size(); i < n; i++)
mSubRuleArray[i] = mSubRules.get(i); // mSubRuleArray[i] = mSubRules.get(i);
mRenderInstructions.clear(); mRenderInstructions.clear();
mRenderInstructions = null; mRenderInstructions = null;

View File

@ -132,11 +132,11 @@
<xs:attribute name="src" type="tns:src" use="optional" /> <xs:attribute name="src" type="tns:src" use="optional" />
<xs:attribute name="stroke" type="tns:color" use="optional" <xs:attribute name="stroke" type="tns:color" use="optional"
default="#000000" /> default="#000000" />
<xs:attribute name="stroke-width" type="tns:nonNegativeFloat" <xs:attribute name="width" type="tns:nonNegativeFloat"
use="optional" default="0" /> use="optional" default="0" />
<xs:attribute name="stroke-dasharray" type="tns:strokeDasharray" <xs:attribute name="stroke-dasharray" type="tns:strokeDasharray"
use="optional" /> use="optional" />
<xs:attribute name="stroke-linecap" type="tns:cap" use="optional" <xs:attribute name="cap" type="tns:cap" use="optional"
default="round" /> default="round" />
<xs:attribute name="outline" type="xs:integer" use="optional" <xs:attribute name="outline" type="xs:integer" use="optional"
default="0" /> default="0" />
@ -163,6 +163,7 @@
</xs:complexType> </xs:complexType>
<xs:complexType name="pathText"> <xs:complexType name="pathText">
<xs:attribute name="style" type="xs:string" use="optional" default="0"/>
<xs:attribute name="k" type="tns:textKey" use="required" /> <xs:attribute name="k" type="tns:textKey" use="required" />
<xs:attribute name="dy" type="xs:float" use="optional" <xs:attribute name="dy" type="xs:float" use="optional"
default="0" /> default="0" />
@ -198,6 +199,7 @@
<xs:element name="outline" type="tns:outline" /> <xs:element name="outline" type="tns:outline" />
<xs:element name="lineSymbol" type="tns:lineSymbol" /> <xs:element name="lineSymbol" type="tns:lineSymbol" />
<xs:element name="pathText" type="tns:pathText" /> <xs:element name="pathText" type="tns:pathText" />
<xs:element name="stylePathText type="xs:string" />
<xs:element name="symbol" type="tns:symbol" /> <xs:element name="symbol" type="tns:symbol" />
</xs:choice> </xs:choice>
<xs:attribute name="e" type="tns:elementList" use="required" /> <xs:attribute name="e" type="tns:elementList" use="required" />
@ -214,6 +216,12 @@
<!-- rendertheme element --> <!-- rendertheme element -->
<xs:complexType name="rendertheme"> <xs:complexType name="rendertheme">
<xs:sequence minOccurs="0" maxOccurds="256">
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="style-pathtext" type="tns:pathText" />
<xs:element name="style-area" type="tns:area" />
</xs:choice>
</xs:sequence)
<xs:sequence minOccurs="0" maxOccurs="unbounded"> <xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element name="rule" type="tns:rule" /> <xs:element name="rule" type="tns:rule" />
</xs:sequence> </xs:sequence>

View File

@ -14,23 +14,17 @@
*/ */
package org.mapsforge.android.rendertheme.renderinstruction; package org.mapsforge.android.rendertheme.renderinstruction;
import java.io.IOException;
import org.mapsforge.android.rendertheme.IRenderCallback; import org.mapsforge.android.rendertheme.IRenderCallback;
import org.mapsforge.android.rendertheme.RenderThemeHandler; import org.mapsforge.android.rendertheme.RenderThemeHandler;
import org.mapsforge.core.Tag; import org.mapsforge.core.Tag;
import org.xml.sax.Attributes; import org.xml.sax.Attributes;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Cap;
import android.graphics.Paint.Style;
import android.graphics.Shader;
/** /**
* Represents a closed polygon on the map. * Represents a closed polygon on the map.
*/ */
public final class Area implements RenderInstruction { public final class Area extends RenderInstruction {
/** /**
* @param elementName * @param elementName
* the name of the XML element. * the name of the XML element.
@ -39,11 +33,8 @@ public final class Area implements RenderInstruction {
* @param level * @param level
* the drawing level of this instruction. * the drawing level of this instruction.
* @return a new Area with the given rendering attributes. * @return a new Area with the given rendering attributes.
* @throws IOException
* if an I/O error occurs while reading a resource.
*/ */
public static Area create(String elementName, Attributes attributes, int level) public static Area create(String elementName, Attributes attributes, int level) {
throws IOException {
String src = null; String src = null;
int fill = Color.BLACK; int fill = Color.BLACK;
int stroke = Color.TRANSPARENT; int stroke = Color.TRANSPARENT;
@ -51,12 +42,14 @@ public final class Area implements RenderInstruction {
int fade = -1; int fade = -1;
int blend = -1; int blend = -1;
int blendFill = Color.BLACK; int blendFill = Color.BLACK;
String style = null;
for (int i = 0; i < attributes.getLength(); ++i) { for (int i = 0; i < attributes.getLength(); ++i) {
String name = attributes.getLocalName(i); String name = attributes.getLocalName(i);
String value = attributes.getValue(i); String value = attributes.getValue(i);
if ("name".equals(name))
if ("src".equals(name)) { style = value;
else if ("src".equals(name)) {
src = value; src = value;
} else if ("fill".equals(name)) { } else if ("fill".equals(name)) {
fill = Color.parseColor(value); fill = Color.parseColor(value);
@ -76,7 +69,8 @@ public final class Area implements RenderInstruction {
} }
validate(strokeWidth); validate(strokeWidth);
return new Area(src, fill, stroke, strokeWidth, fade, level, blend, blendFill); return new Area(style, src, fill, stroke, strokeWidth, fade, level, blend,
blendFill);
} }
private static void validate(float strokeWidth) { private static void validate(float strokeWidth) {
@ -86,32 +80,38 @@ public final class Area implements RenderInstruction {
} }
} }
private Area(String src, int fill, int stroke, float strokeWidth, int fade, private Area(String style, String src, int fill, int stroke, float strokeWidth,
int level, int blend, int blendFill) int fade, int level, int blend, int blendFill) {
throws IOException {
super(); super();
this.style = style;
if (fill == Color.TRANSPARENT) { // if (fill == Color.TRANSPARENT) {
paintFill = null; // paintFill = null;
} else { // } else {
paintFill = new Paint(Paint.ANTI_ALIAS_FLAG); // paintFill = new Paint(Paint.ANTI_ALIAS_FLAG);
if (src != null) { // if (src != null) {
Shader shader = BitmapUtils.createBitmapShader(src); // Shader shader = BitmapUtils.createBitmapShader(src);
paintFill.setShader(shader); // paintFill.setShader(shader);
} // }
paintFill.setStyle(Style.FILL); // paintFill.setStyle(Style.FILL);
paintFill.setColor(fill); // paintFill.setColor(fill);
paintFill.setStrokeCap(Cap.ROUND); // paintFill.setStrokeCap(Cap.ROUND);
} // }
//
// if (stroke == Color.TRANSPARENT) {
// paintOutline = null;
// } else {
// paintOutline = new Paint(Paint.ANTI_ALIAS_FLAG);
// paintOutline.setStyle(Style.STROKE);
// paintOutline.setColor(stroke);
// paintOutline.setStrokeCap(Cap.ROUND);
// }
if (stroke == Color.TRANSPARENT) { // if (stroke == Color.TRANSPARENT) {
paintOutline = null; // stroke = null;
} else { // } else{
paintOutline = new Paint(Paint.ANTI_ALIAS_FLAG); // stroke = new Line()
paintOutline.setStyle(Style.STROKE); // }
paintOutline.setColor(stroke);
paintOutline.setStrokeCap(Cap.ROUND);
}
color = new float[4]; color = new float[4];
color[0] = (fill >> 16 & 0xff) / 255.0f; color[0] = (fill >> 16 & 0xff) / 255.0f;
@ -135,47 +135,31 @@ public final class Area implements RenderInstruction {
this.level = level; this.level = level;
} }
@Override
public void destroy() {
// do nothing
}
@Override
public void renderNode(IRenderCallback renderCallback, Tag[] tags) {
// do nothing
}
@Override @Override
public void renderWay(IRenderCallback renderCallback, Tag[] tags) { public void renderWay(IRenderCallback renderCallback, Tag[] tags) {
if (paintFill != null) { renderCallback.renderArea(this, this.level);
renderCallback.renderArea(this);
}
} }
@Override // @Override
public void scaleStrokeWidth(float scaleFactor) { // public void scaleStrokeWidth(float scaleFactor) {
if (paintOutline != null) { // // if (paintOutline != null) {
paintOutline.setStrokeWidth(strokeWidth * scaleFactor); // // paintOutline.setStrokeWidth(strokeWidth * scaleFactor);
} // // }
} // }
@Override
public void scaleTextSize(float scaleFactor) {
// do nothing
}
public String style;
/** /**
* *
*/ */
public final int level; private final int level;
/** /**
* *
*/ */
public final Paint paintFill; // public final Paint paintFill;
/** /**
* *
*/ */
public final Paint paintOutline; // public final Paint paintOutline;
/** /**
* *
*/ */

View File

@ -12,17 +12,22 @@
* You should have received a copy of the GNU Lesser General Public License along with * You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>. * this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package org.mapsforge.android.glrenderer; package org.mapsforge.android.rendertheme.renderinstruction;
import java.util.ArrayList; import org.mapsforge.android.rendertheme.IRenderCallback;
import org.mapsforge.core.Tag;
import org.mapsforge.android.rendertheme.renderinstruction.Caption; public class AreaLevel extends RenderInstruction {
private final Area area;
public class TextLayer { private final int level;
public ArrayList<TextItem> labels;
void addLabel(float x, float y, String text, Caption caption) {
public AreaLevel(Area area, int level) {
this.area = area;
this.level = level;
} }
@Override
public void renderWay(IRenderCallback renderCallback, Tag[] tags) {
renderCallback.renderArea(this.area, level);
}
} }

View File

@ -32,7 +32,7 @@ import android.util.FloatMath;
/** /**
* Represents a text label on the map. * Represents a text label on the map.
*/ */
public final class Caption implements RenderInstruction { public final class Caption extends RenderInstruction {
/** /**
* @param elementName * @param elementName
* the name of the XML element. * the name of the XML element.
@ -130,11 +130,6 @@ public final class Caption implements RenderInstruction {
fontDescent = FloatMath.ceil(Math.abs(fm.descent)); fontDescent = FloatMath.ceil(Math.abs(fm.descent));
} }
@Override
public void destroy() {
// do nothing
}
@Override @Override
public void renderNode(IRenderCallback renderCallback, Tag[] tags) { public void renderNode(IRenderCallback renderCallback, Tag[] tags) {
renderCallback.renderPointOfInterestCaption(this); renderCallback.renderPointOfInterestCaption(this);
@ -145,11 +140,6 @@ public final class Caption implements RenderInstruction {
renderCallback.renderAreaCaption(this); renderCallback.renderAreaCaption(this);
} }
@Override
public void scaleStrokeWidth(float scaleFactor) {
// do nothing
}
@Override @Override
public void scaleTextSize(float scaleFactor) { public void scaleTextSize(float scaleFactor) {
paint.setTextSize(fontSize * scaleFactor); paint.setTextSize(fontSize * scaleFactor);

View File

@ -26,7 +26,7 @@ import android.graphics.Paint.Style;
/** /**
* Represents a round area on the map. * Represents a round area on the map.
*/ */
public final class Circle implements RenderInstruction { public final class Circle extends RenderInstruction {
/** /**
* @param elementName * @param elementName
* the name of the XML element. * the name of the XML element.
@ -68,11 +68,13 @@ public final class Circle implements RenderInstruction {
private static void validate(String elementName, Float radius, float strokeWidth) { private static void validate(String elementName, Float radius, float strokeWidth) {
if (radius == null) { if (radius == null) {
throw new IllegalArgumentException("missing attribute r for element: " + elementName); throw new IllegalArgumentException("missing attribute r for element: "
+ elementName);
} else if (radius.floatValue() < 0) { } else if (radius.floatValue() < 0) {
throw new IllegalArgumentException("radius must not be negative: " + radius); throw new IllegalArgumentException("radius must not be negative: " + radius);
} else if (strokeWidth < 0) { } else if (strokeWidth < 0) {
throw new IllegalArgumentException("stroke-width must not be negative: " + strokeWidth); throw new IllegalArgumentException("stroke-width must not be negative: "
+ strokeWidth);
} }
} }
@ -84,7 +86,8 @@ public final class Circle implements RenderInstruction {
private final boolean mScaleRadius; private final boolean mScaleRadius;
private final float mStrokeWidth; private final float mStrokeWidth;
private Circle(Float radius, boolean scaleRadius, int fill, int stroke, float strokeWidth, int level) { private Circle(Float radius, boolean scaleRadius, int fill, int stroke,
float strokeWidth, int level) {
super(); super();
mRadius = radius.floatValue(); mRadius = radius.floatValue();
@ -117,11 +120,6 @@ public final class Circle implements RenderInstruction {
} }
} }
@Override
public void destroy() {
// do nothing
}
@Override @Override
public void renderNode(IRenderCallback renderCallback, Tag[] tags) { public void renderNode(IRenderCallback renderCallback, Tag[] tags) {
if (mOutline != null) { if (mOutline != null) {
@ -132,11 +130,6 @@ public final class Circle implements RenderInstruction {
} }
} }
@Override
public void renderWay(IRenderCallback renderCallback, Tag[] tags) {
// do nothing
}
@Override @Override
public void scaleStrokeWidth(float scaleFactor) { public void scaleStrokeWidth(float scaleFactor) {
if (mScaleRadius) { if (mScaleRadius) {
@ -146,9 +139,4 @@ public final class Circle implements RenderInstruction {
} }
} }
} }
@Override
public void scaleTextSize(float scaleFactor) {
// do nothing
}
} }

View File

@ -14,7 +14,6 @@
*/ */
package org.mapsforge.android.rendertheme.renderinstruction; package org.mapsforge.android.rendertheme.renderinstruction;
import java.io.IOException;
import java.util.Locale; import java.util.Locale;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -24,73 +23,94 @@ import org.mapsforge.core.Tag;
import org.xml.sax.Attributes; import org.xml.sax.Attributes;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Paint.Cap; import android.graphics.Paint.Cap;
import android.graphics.Paint.Style;
import android.graphics.Shader;
/** /**
* Represents a polyline on the map. * Represents a polyline on the map.
*/ */
public final class Line implements RenderInstruction { public final class Line extends RenderInstruction {
private static final Pattern SPLIT_PATTERN = Pattern.compile(","); private static final Pattern SPLIT_PATTERN = Pattern.compile(",");
/** /**
* @param line
* ...
* @param elementName * @param elementName
* the name of the XML element. * the name of the XML element.
* @param attributes * @param attributes
* the attributes of the XML element. * the attributes of the XML element.
* @param level * @param level
* the drawing level of this instruction. * the drawing level of this instruction.
* @param isOutline
* ...
* @return a new Line with the given rendering attributes. * @return a new Line with the given rendering attributes.
* @throws IOException
* if an I/O error occurs while reading a resource.
*/ */
public static Line create(String elementName, Attributes attributes, int level) public static Line create(Line line, String elementName, Attributes attributes,
throws IOException { int level, boolean isOutline) {
String src = null; String src = null;
int stroke = Color.BLACK; int stroke = Color.BLACK;
float strokeWidth = 0; float strokeWidth = 0;
float[] strokeDasharray = null; float[] strokeDasharray = null;
Cap strokeLinecap = Cap.ROUND; Cap strokeLinecap = Cap.ROUND;
int outline = -1;
int fade = -1; int fade = -1;
boolean fixed = false; boolean fixed = false;
String style = null;
float blur = 0;
if (line != null) {
fixed = line.fixed;
fade = line.fade;
strokeLinecap = line.cap;
blur = line.blur;
}
for (int i = 0; i < attributes.getLength(); ++i) { for (int i = 0; i < attributes.getLength(); ++i) {
String name = attributes.getLocalName(i); String name = attributes.getLocalName(i);
String value = attributes.getValue(i); String value = attributes.getValue(i);
if ("src".equals(name)) { if ("name".equals(name))
style = value;
else if ("src".equals(name)) {
src = value; src = value;
} else if ("stroke".equals(name)) { } else if ("stroke".equals(name)) {
stroke = Color.parseColor(value); stroke = Color.parseColor(value);
} else if ("stroke-width".equals(name)) { } else if ("width".equals(name)) {
strokeWidth = Float.parseFloat(value); strokeWidth = Float.parseFloat(value);
} else if ("stroke-dasharray".equals(name)) { } else if ("stroke-dasharray".equals(name)) {
strokeDasharray = parseFloatArray(value); strokeDasharray = parseFloatArray(value);
} else if ("stroke-linecap".equals(name)) { } else if ("cap".equals(name)) {
strokeLinecap = Cap.valueOf(value.toUpperCase(Locale.ENGLISH)); strokeLinecap = Cap.valueOf(value.toUpperCase(Locale.ENGLISH));
} else if ("outline".equals(name)) {
outline = Integer.parseInt(value);
} else if ("fade".equals(name)) { } else if ("fade".equals(name)) {
fade = Integer.parseInt(value); fade = Integer.parseInt(value);
} else if ("fixed".equals(name)) { } else if ("fixed".equals(name)) {
fixed = Boolean.parseBoolean(value); fixed = Boolean.parseBoolean(value);
} else if ("blur".equals(name)) {
blur = Float.parseFloat(value);
} else if ("from".equals(name)) {
} else { } else {
RenderThemeHandler.logUnknownAttribute(elementName, name, value, i); RenderThemeHandler.logUnknownAttribute(elementName, name, value, i);
} }
} }
if (line != null) {
strokeWidth = line.width + strokeWidth;
if (strokeWidth <= 0)
strokeWidth = 1;
return new Line(line, style, src, stroke, strokeWidth, strokeDasharray,
strokeLinecap, level, fixed, fade, blur, isOutline);
}
if (!isOutline)
validate(strokeWidth); validate(strokeWidth);
return new Line(src, stroke, strokeWidth, strokeDasharray, strokeLinecap, level,
outline, fixed, fade); return new Line(style, src, stroke, strokeWidth, strokeDasharray, strokeLinecap,
level, fixed, fade, blur, isOutline);
} }
private static void validate(float strokeWidth) { private static void validate(float strokeWidth) {
if (strokeWidth < 0) { if (strokeWidth < 0) {
throw new IllegalArgumentException("stroke-width must not be negative: " throw new IllegalArgumentException("width must not be negative: "
+ strokeWidth); + strokeWidth);
} }
} }
@ -107,15 +127,15 @@ public final class Line implements RenderInstruction {
/** /**
* *
*/ */
public final int level; private final int level;
/** /**
* *
*/ */
public final Paint paint; // public final Paint paint;
/** /**
* *
*/ */
public final float strokeWidth; public final float width;
/** /**
* *
*/ */
@ -127,7 +147,7 @@ public final class Line implements RenderInstruction {
/** /**
* *
*/ */
public final int outline; public final boolean outline;
/** /**
* *
@ -136,60 +156,83 @@ public final class Line implements RenderInstruction {
public final int fade; public final int fade;
private Line(String src, int stroke, float strokeWidth, float[] strokeDasharray, public final String style;
Cap strokeLinecap, int level,
int outline, boolean fixed, int fade) public final Cap cap;
throws IOException {
public final float blur;
private Line(String style, String src, int stroke, float strokeWidth,
float[] strokeDasharray, Cap strokeLinecap, int level, boolean fixed,
int fade, float blur, boolean isOutline) {
super(); super();
Shader shader = BitmapUtils.createBitmapShader(src); this.style = style;
// paint = new Paint(Paint.ANTI_ALIAS_FLAG);
//
// if (src != null) {
// Shader shader = BitmapUtils.createBitmapShader(src);
// paint.setShader(shader);
// }
//
// paint.setStyle(Style.STROKE);
// paint.setColor(stroke);
// if (strokeDasharray != null) {
// paint.setPathEffect(new DashPathEffect(strokeDasharray, 0));
// }
// paint.setStrokeCap(strokeLinecap);
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setShader(shader);
paint.setStyle(Style.STROKE);
paint.setColor(stroke);
if (strokeDasharray != null) {
paint.setPathEffect(new DashPathEffect(strokeDasharray, 0));
}
paint.setStrokeCap(strokeLinecap);
round = (strokeLinecap == Cap.ROUND); round = (strokeLinecap == Cap.ROUND);
this.cap = strokeLinecap;
color = new float[4]; color = new float[4];
color[0] = (stroke >> 16 & 0xff) / 255.0f; color[0] = (stroke >> 16 & 0xff) / 255.0f;
color[1] = (stroke >> 8 & 0xff) / 255.0f; color[1] = (stroke >> 8 & 0xff) / 255.0f;
color[2] = (stroke >> 0 & 0xff) / 255.0f; color[2] = (stroke >> 0 & 0xff) / 255.0f;
color[3] = (stroke >> 24 & 0xff) / 255.0f; color[3] = (stroke >> 24 & 0xff) / 255.0f;
this.strokeWidth = strokeWidth; this.width = strokeWidth;
this.level = level; this.level = level;
this.outline = outline; this.outline = isOutline;
this.fixed = fixed; this.fixed = fixed;
this.blur = blur;
this.fade = fade; this.fade = fade;
} }
@Override private Line(Line line, String style, String src, int stroke, float strokeWidth,
public void destroy() { float[] strokeDasharray, Cap strokeLinecap, int level, boolean fixed,
// do nothing int fade, float blur, boolean isOutline) {
} super();
@Override this.style = style;
public void renderNode(IRenderCallback renderCallback, Tag[] tags) {
// do nothing round = (strokeLinecap == Cap.ROUND);
color = line.color;
this.width = strokeWidth;
this.level = level;
this.outline = isOutline;
this.fixed = fixed;
this.fade = fade;
this.cap = strokeLinecap;
this.blur = blur;
} }
@Override @Override
public void renderWay(IRenderCallback renderCallback, Tag[] tags) { public void renderWay(IRenderCallback renderCallback, Tag[] tags) {
// renderCallback.renderWay(mPaint, mLevel, mColor, mStrokeWidth, mRound, mOutline); // renderCallback.renderWay(mPaint, mLevel, mColor, mStrokeWidth, mRound, mOutline);
renderCallback.renderWay(this); renderCallback.renderWay(this, level);
} }
@Override // @Override
public void scaleStrokeWidth(float scaleFactor) { // public void scaleStrokeWidth(float scaleFactor) {
paint.setStrokeWidth(strokeWidth * scaleFactor); // paint.setStrokeWidth(strokeWidth * scaleFactor);
} // }
@Override public int getLevel() {
public void scaleTextSize(float scaleFactor) { return this.level;
// do nothing
} }
} }

View File

@ -26,7 +26,7 @@ import android.graphics.Bitmap;
/** /**
* Represents an icon along a polyline on the map. * Represents an icon along a polyline on the map.
*/ */
public final class LineSymbol implements RenderInstruction { public final class LineSymbol extends RenderInstruction {
/** /**
* @param elementName * @param elementName
* the name of the XML element. * the name of the XML element.
@ -36,7 +36,8 @@ public final class LineSymbol implements RenderInstruction {
* @throws IOException * @throws IOException
* if an I/O error occurs while reading a resource. * if an I/O error occurs while reading a resource.
*/ */
public static LineSymbol create(String elementName, Attributes attributes) throws IOException { public static LineSymbol create(String elementName, Attributes attributes)
throws IOException {
String src = null; String src = null;
boolean alignCenter = false; boolean alignCenter = false;
boolean repeat = false; boolean repeat = false;
@ -62,7 +63,8 @@ public final class LineSymbol implements RenderInstruction {
private static void validate(String elementName, String src) { private static void validate(String elementName, String src) {
if (src == null) { if (src == null) {
throw new IllegalArgumentException("missing attribute src for element: " + elementName); throw new IllegalArgumentException("missing attribute src for element: "
+ elementName);
} }
} }
@ -70,7 +72,8 @@ public final class LineSymbol implements RenderInstruction {
private final Bitmap mBitmap; private final Bitmap mBitmap;
private final boolean mRepeat; private final boolean mRepeat;
private LineSymbol(String src, boolean alignCenter, boolean repeat) throws IOException { private LineSymbol(String src, boolean alignCenter, boolean repeat)
throws IOException {
super(); super();
mBitmap = BitmapUtils.createBitmap(src); mBitmap = BitmapUtils.createBitmap(src);
@ -83,23 +86,8 @@ public final class LineSymbol implements RenderInstruction {
mBitmap.recycle(); mBitmap.recycle();
} }
@Override
public void renderNode(IRenderCallback renderCallback, Tag[] tags) {
// do nothing
}
@Override @Override
public void renderWay(IRenderCallback renderCallback, Tag[] tags) { public void renderWay(IRenderCallback renderCallback, Tag[] tags) {
renderCallback.renderWaySymbol(mBitmap, mAlignCenter, mRepeat); renderCallback.renderWaySymbol(mBitmap, mAlignCenter, mRepeat);
} }
@Override
public void scaleStrokeWidth(float scaleFactor) {
// do nothing
}
@Override
public void scaleTextSize(float scaleFactor) {
// do nothing
}
} }

View File

@ -24,13 +24,15 @@ import org.xml.sax.Attributes;
import android.graphics.Color; import android.graphics.Color;
import android.graphics.Paint; import android.graphics.Paint;
import android.graphics.Paint.Align; import android.graphics.Paint.Align;
import android.graphics.Paint.FontMetrics;
import android.graphics.Paint.Style; import android.graphics.Paint.Style;
import android.graphics.Typeface; import android.graphics.Typeface;
import android.util.FloatMath;
/** /**
* Represents a text along a polyline on the map. * Represents a text along a polyline on the map.
*/ */
public final class PathText implements RenderInstruction { public final class PathText extends RenderInstruction {
/** /**
* @param elementName * @param elementName
* the name of the XML element. * the name of the XML element.
@ -46,12 +48,14 @@ public final class PathText implements RenderInstruction {
int fill = Color.BLACK; int fill = Color.BLACK;
int stroke = Color.BLACK; int stroke = Color.BLACK;
float strokeWidth = 0; float strokeWidth = 0;
String style = null;
for (int i = 0; i < attributes.getLength(); ++i) { for (int i = 0; i < attributes.getLength(); ++i) {
String name = attributes.getLocalName(i); String name = attributes.getLocalName(i);
String value = attributes.getValue(i); String value = attributes.getValue(i);
if ("name".equals(name))
if ("k".equals(name)) { style = value;
else if ("k".equals(name)) {
textKey = TextKey.getInstance(value); textKey = TextKey.getInstance(value);
} else if ("font-family".equals(name)) { } else if ("font-family".equals(name)) {
fontFamily = FontFamily.valueOf(value.toUpperCase(Locale.ENGLISH)); fontFamily = FontFamily.valueOf(value.toUpperCase(Locale.ENGLISH));
@ -72,67 +76,69 @@ public final class PathText implements RenderInstruction {
validate(elementName, textKey, fontSize, strokeWidth); validate(elementName, textKey, fontSize, strokeWidth);
Typeface typeface = Typeface.create(fontFamily.toTypeface(), fontStyle.toInt()); Typeface typeface = Typeface.create(fontFamily.toTypeface(), fontStyle.toInt());
return new PathText(textKey, typeface, fontSize, fill, stroke, strokeWidth); return new PathText(style, textKey, typeface, fontSize, fill, stroke, strokeWidth);
} }
private static void validate(String elementName, String textKey, float fontSize, float strokeWidth) { private static void validate(String elementName, String textKey, float fontSize,
float strokeWidth) {
if (textKey == null) { if (textKey == null) {
throw new IllegalArgumentException("missing attribute k for element: " + elementName); throw new IllegalArgumentException("missing attribute k for element: "
+ elementName);
} else if (fontSize < 0) { } else if (fontSize < 0) {
throw new IllegalArgumentException("font-size must not be negative: " + fontSize); throw new IllegalArgumentException("font-size must not be negative: "
+ fontSize);
} else if (strokeWidth < 0) { } else if (strokeWidth < 0) {
throw new IllegalArgumentException("stroke-width must not be negative: " + strokeWidth); throw new IllegalArgumentException("stroke-width must not be negative: "
+ strokeWidth);
} }
} }
private final float mFontSize; public final float fontSize;
private final Paint mPaint; public final Paint paint;
private final Paint mStroke; public Paint stroke;
private final String mTextKey; public String textKey;
public final float fontHeight;
public final float fontDescent;
public String style;
private PathText(String textKey, Typeface typeface, float fontSize, int fill, int stroke, float strokeWidth) { private PathText(String style, String textKey, Typeface typeface, float fontSize,
int fill, int outline, float strokeWidth) {
super(); super();
mTextKey = textKey; this.style = style;
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); this.textKey = textKey;
mPaint.setTextAlign(Align.CENTER);
mPaint.setTypeface(typeface);
mPaint.setColor(fill);
mStroke = new Paint(Paint.ANTI_ALIAS_FLAG); paint = new Paint(Paint.ANTI_ALIAS_FLAG);
mStroke.setStyle(Style.STROKE); paint.setTextAlign(Align.CENTER);
mStroke.setTextAlign(Align.CENTER); paint.setTypeface(typeface);
mStroke.setTypeface(typeface); paint.setColor(fill);
mStroke.setColor(stroke);
mStroke.setStrokeWidth(strokeWidth);
mFontSize = fontSize; stroke = new Paint(Paint.ANTI_ALIAS_FLAG);
} stroke.setStyle(Style.STROKE);
stroke.setTextAlign(Align.CENTER);
stroke.setTypeface(typeface);
stroke.setColor(outline);
stroke.setStrokeWidth(strokeWidth);
@Override this.fontSize = fontSize;
public void destroy() {
// do nothing
}
@Override paint.setTextSize(fontSize);
public void renderNode(IRenderCallback renderCallback, Tag[] tags) { stroke.setTextSize(fontSize);
// do nothing
FontMetrics fm = paint.getFontMetrics();
fontHeight = FloatMath.ceil(Math.abs(fm.bottom) + Math.abs(fm.top));
fontDescent = FloatMath.ceil(Math.abs(fm.descent));
} }
@Override @Override
public void renderWay(IRenderCallback renderCallback, Tag[] tags) { public void renderWay(IRenderCallback renderCallback, Tag[] tags) {
renderCallback.renderWayText(mTextKey, mPaint, mStroke); renderCallback.renderWayText(this);
}
@Override
public void scaleStrokeWidth(float scaleFactor) {
// do nothing
} }
@Override @Override
public void scaleTextSize(float scaleFactor) { public void scaleTextSize(float scaleFactor) {
mPaint.setTextSize(mFontSize * scaleFactor); paint.setTextSize(fontSize * scaleFactor);
mStroke.setTextSize(mFontSize * scaleFactor); stroke.setTextSize(fontSize * scaleFactor);
} }
} }

View File

@ -20,11 +20,12 @@ import org.mapsforge.core.Tag;
/** /**
* A RenderInstruction is a basic graphical primitive to draw a map. * A RenderInstruction is a basic graphical primitive to draw a map.
*/ */
public interface RenderInstruction { public abstract class RenderInstruction {
/** /**
* Destroys this RenderInstruction and cleans up all its internal resources. * Destroys this RenderInstruction and cleans up all its internal resources.
*/ */
void destroy(); public void destroy() {
}
/** /**
* @param renderCallback * @param renderCallback
@ -32,7 +33,8 @@ public interface RenderInstruction {
* @param tags * @param tags
* the tags of the node. * the tags of the node.
*/ */
void renderNode(IRenderCallback renderCallback, Tag[] tags); public void renderNode(IRenderCallback renderCallback, Tag[] tags) {
}
/** /**
* @param renderCallback * @param renderCallback
@ -40,7 +42,8 @@ public interface RenderInstruction {
* @param tags * @param tags
* the tags of the way. * the tags of the way.
*/ */
void renderWay(IRenderCallback renderCallback, Tag[] tags); public void renderWay(IRenderCallback renderCallback, Tag[] tags) {
}
/** /**
* Scales the stroke width of this RenderInstruction by the given factor. * Scales the stroke width of this RenderInstruction by the given factor.
@ -48,7 +51,8 @@ public interface RenderInstruction {
* @param scaleFactor * @param scaleFactor
* the factor by which the stroke width should be scaled. * the factor by which the stroke width should be scaled.
*/ */
void scaleStrokeWidth(float scaleFactor); public void scaleStrokeWidth(float scaleFactor) {
}
/** /**
* Scales the text size of this RenderInstruction by the given factor. * Scales the text size of this RenderInstruction by the given factor.
@ -56,5 +60,6 @@ public interface RenderInstruction {
* @param scaleFactor * @param scaleFactor
* the factor by which the text size should be scaled. * the factor by which the text size should be scaled.
*/ */
void scaleTextSize(float scaleFactor); public void scaleTextSize(float scaleFactor) {
}
} }

View File

@ -26,7 +26,7 @@ import android.graphics.Bitmap;
/** /**
* Represents an icon on the map. * Represents an icon on the map.
*/ */
public final class Symbol implements RenderInstruction { public final class Symbol extends RenderInstruction {
/** /**
* @param elementName * @param elementName
* the name of the XML element. * the name of the XML element.
@ -36,7 +36,8 @@ public final class Symbol implements RenderInstruction {
* @throws IOException * @throws IOException
* if an I/O error occurs while reading a resource. * if an I/O error occurs while reading a resource.
*/ */
public static Symbol create(String elementName, Attributes attributes) throws IOException { public static Symbol create(String elementName, Attributes attributes)
throws IOException {
String src = null; String src = null;
for (int i = 0; i < attributes.getLength(); ++i) { for (int i = 0; i < attributes.getLength(); ++i) {
@ -56,7 +57,8 @@ public final class Symbol implements RenderInstruction {
private static void validate(String elementName, String src) { private static void validate(String elementName, String src) {
if (src == null) { if (src == null) {
throw new IllegalArgumentException("missing attribute src for element: " + elementName); throw new IllegalArgumentException("missing attribute src for element: "
+ elementName);
} }
} }
@ -82,14 +84,4 @@ public final class Symbol implements RenderInstruction {
public void renderWay(IRenderCallback renderCallback, Tag[] tags) { public void renderWay(IRenderCallback renderCallback, Tag[] tags) {
renderCallback.renderAreaSymbol(mBitmap); renderCallback.renderAreaSymbol(mBitmap);
} }
@Override
public void scaleStrokeWidth(float scaleFactor) {
// do nothing
}
@Override
public void scaleTextSize(float scaleFactor) {
// do nothing
}
} }

View File

@ -24,6 +24,7 @@ import org.mapsforge.android.rendertheme.RenderTheme;
import org.mapsforge.android.rendertheme.renderinstruction.Area; import org.mapsforge.android.rendertheme.renderinstruction.Area;
import org.mapsforge.android.rendertheme.renderinstruction.Caption; import org.mapsforge.android.rendertheme.renderinstruction.Caption;
import org.mapsforge.android.rendertheme.renderinstruction.Line; import org.mapsforge.android.rendertheme.renderinstruction.Line;
import org.mapsforge.android.rendertheme.renderinstruction.PathText;
import org.mapsforge.core.Tag; import org.mapsforge.core.Tag;
import org.mapsforge.core.Tile; import org.mapsforge.core.Tile;
import org.mapsforge.database.IMapDatabase; import org.mapsforge.database.IMapDatabase;
@ -414,24 +415,24 @@ public class MapGenerator implements IMapGenerator, IRenderCallback,
private List<ShapeContainer> mCurLevelContainer2; private List<ShapeContainer> mCurLevelContainer2;
@Override @Override
public void renderWay(Line line) { public void renderWay(Line line, int level) {
List<ShapeContainer> c = mDrawingLayer.add(line.level, mWayDataContainer, // List<ShapeContainer> c = mDrawingLayer.add(level, mWayDataContainer,
line.paint); // line.paint);
//
if (mCurLevelContainer1 == null) // if (mCurLevelContainer1 == null)
mCurLevelContainer1 = c; // mCurLevelContainer1 = c;
else if (mCurLevelContainer2 == null) // else if (mCurLevelContainer2 == null)
mCurLevelContainer2 = c; // mCurLevelContainer2 = c;
} }
@Override @Override
public void renderArea(Area area) { public void renderArea(Area area, int level) {
if (area.paintFill != null) // if (area.paintFill != null)
mCurLevelContainer1 = mDrawingLayer.add(area.level, mWayDataContainer, // mCurLevelContainer1 = mDrawingLayer.add(level, mWayDataContainer,
area.paintFill); // area.paintFill);
if (area.paintOutline != null) // if (area.paintOutline != null)
mCurLevelContainer1 = mDrawingLayer.add(area.level, mWayDataContainer, // mCurLevelContainer1 = mDrawingLayer.add(level, mWayDataContainer,
area.paintOutline); // area.paintOutline);
} }
@Override @Override
@ -443,7 +444,7 @@ public class MapGenerator implements IMapGenerator, IRenderCallback,
} }
@Override @Override
public void renderWayText(String textKey, Paint paint, Paint outline) { public void renderWayText(PathText pathText) {
// if (mWayDataContainer.textPos[0] >= 0) // if (mWayDataContainer.textPos[0] >= 0)
// WayDecorator.renderText(this, paint, outline, mCoords, mWayDataContainer, mWayNames); // WayDecorator.renderText(this, paint, outline, mCoords, mWayDataContainer, mWayNames);
} }

View File

@ -33,6 +33,7 @@ import org.mapsforge.android.mapgenerator.JobParameters;
import org.mapsforge.android.mapgenerator.MapGeneratorJob; import org.mapsforge.android.mapgenerator.MapGeneratorJob;
import org.mapsforge.android.mapgenerator.TileCacheKey; import org.mapsforge.android.mapgenerator.TileCacheKey;
import org.mapsforge.android.mapgenerator.TileDistanceSort; import org.mapsforge.android.mapgenerator.TileDistanceSort;
import org.mapsforge.android.rendertheme.RenderTheme;
import org.mapsforge.android.utils.GlUtils; import org.mapsforge.android.utils.GlUtils;
import org.mapsforge.core.MapPosition; import org.mapsforge.core.MapPosition;
import org.mapsforge.core.MercatorProjection; import org.mapsforge.core.MercatorProjection;
@ -213,7 +214,7 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
newTiles[tiles++] = tile; newTiles[tiles++] = tile;
if (!tile.isReady || (tile.getScale() != scale)) { if (!tile.isReady || (tile.getScale() != scale)) {
tile.isLoading = true; // tile.isLoading = true;
// approximation for TileScheduler // approximation for TileScheduler
if (tileY < tileTop || tileY > tileBottom || tileX < tileLeft if (tileY < tileTop || tileY > tileBottom || tileX < tileLeft
|| tileX > tileRight) || tileX > tileRight)
@ -494,12 +495,6 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
} }
} }
} }
// FIXME
// if (loadedTexture) {
// synchronized (mMapWorker) {
// mMapWorker.notify();
// }
// }
} }
@Override @Override
@ -588,4 +583,10 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
public IMapGenerator createMapGenerator() { public IMapGenerator createMapGenerator() {
return new MapGenerator(); return new MapGenerator();
} }
@Override
public void setRenderTheme(RenderTheme t) {
// TODO Auto-generated method stub
}
} }

View File

@ -38,7 +38,8 @@ final class WayDecorator {
*/ */
private static final int SEGMENT_SAFETY_DISTANCE = 30; private static final int SEGMENT_SAFETY_DISTANCE = 30;
static void renderSymbol(Bitmap symbolBitmap, boolean alignCenter, boolean repeatSymbol, float[][] coordinates, static void renderSymbol(Bitmap symbolBitmap, boolean alignCenter,
boolean repeatSymbol, float[][] coordinates,
List<SymbolContainer> waySymbols) { List<SymbolContainer> waySymbols) {
int skipPixels = SEGMENT_SAFETY_DISTANCE; int skipPixels = SEGMENT_SAFETY_DISTANCE;
@ -68,9 +69,11 @@ final class WayDecorator {
// move the previous point forward towards the current point // move the previous point forward towards the current point
previousX += diffX * segmentSkipPercentage; previousX += diffX * segmentSkipPercentage;
previousY += diffY * segmentSkipPercentage; previousY += diffY * segmentSkipPercentage;
symbolAngle = (float) Math.toDegrees(Math.atan2(currentY - previousY, currentX - previousX)); symbolAngle = (float) Math.toDegrees(Math.atan2(currentY - previousY,
currentX - previousX));
waySymbols.add(new SymbolContainer(symbolBitmap, previousX, previousY, alignCenter, symbolAngle)); waySymbols.add(new SymbolContainer(symbolBitmap, previousX, previousY,
alignCenter, symbolAngle));
// check if the symbol should only be rendered once // check if the symbol should only be rendered once
if (!repeatSymbol) { if (!repeatSymbol) {
@ -145,7 +148,8 @@ final class WayDecorator {
} else if ((currentY - nextY) == 0) } else if ((currentY - nextY) == 0)
break; break;
float diff = ((float) (diffX) / (diffY) - (float) (currentX - nextX) / (currentY - nextY)); float diff = ((float) (diffX) / (diffY) - (float) (currentX - nextX)
/ (currentY - nextY));
// skip segments with corners // skip segments with corners
if (diff >= 0.2 || diff <= -0.2) if (diff >= 0.2 || diff <= -0.2)
@ -210,7 +214,7 @@ final class WayDecorator {
y2 = previousY; y2 = previousY;
} }
// estimate position of test on path // estimate position of text on path
width = (x2 - x1) / 2; width = (x2 - x1) / 2;
x2 = x2 - (int) (width - s * width); x2 = x2 - (int) (width - s * width);
x1 = x1 + (int) (width - s * width); x1 = x1 + (int) (width - s * width);
@ -234,7 +238,8 @@ final class WayDecorator {
break; break;
// check crossings // check crossings
if (GeometryUtils.lineIntersect(x1, y1, x2, y2, wtc2.x1, wtc2.y1, wtc2.x2, wtc2.y2)) { if (GeometryUtils.lineIntersect(x1, y1, x2, y2, wtc2.x1, wtc2.y1,
wtc2.x2, wtc2.y2)) {
intersects = true; intersects = true;
break; break;
} }
@ -244,7 +249,8 @@ final class WayDecorator {
short top2 = (wtc2.y1 < wtc2.y2 ? wtc2.y1 : wtc2.y2); short top2 = (wtc2.y1 < wtc2.y2 ? wtc2.y1 : wtc2.y2);
short bot2 = (wtc2.y1 < wtc2.y2 ? wtc2.y2 : wtc2.y1); short bot2 = (wtc2.y1 < wtc2.y2 ? wtc2.y2 : wtc2.y1);
if (x1 - 10 < wtc2.x2 && wtc2.x1 - 10 < x2 && top - 10 < bot2 && top2 - 10 < bot) { if (x1 - 10 < wtc2.x2 && wtc2.x1 - 10 < x2 && top - 10 < bot2
&& top2 - 10 < bot) {
if (wtc2.text.equals(text)) { if (wtc2.text.equals(text)) {
intersects = true; intersects = true;
@ -260,7 +266,8 @@ final class WayDecorator {
} }
Log.d("mapsforge", "add " + text + " " + first + " " + last); Log.d("mapsforge", "add " + text + " " + first + " " + last);
WayTextContainer wtc = new WayTextContainer(first, last, wayDataContainer, text, WayTextContainer wtc = new WayTextContainer(first, last,
wayDataContainer, text,
paint); paint);
wtc.x1 = (short) x1; wtc.x1 = (short) x1;
wtc.y1 = (short) y1; wtc.y1 = (short) y1;
@ -272,7 +279,8 @@ final class WayDecorator {
containerSize++; containerSize++;
if (outline != null) { if (outline != null) {
wayNames.add(new WayTextContainer(first, last, wayDataContainer, text, outline)); wayNames.add(new WayTextContainer(first, last, wayDataContainer,
text, outline));
containerSize++; containerSize++;
} }
// 500 ??? how big is a tile?! // 500 ??? how big is a tile?!

View File

@ -29,7 +29,7 @@ public class GlConfigChooser implements GLSurfaceView.EGLConfigChooser {
EGL10.EGL_GREEN_SIZE, 6, EGL10.EGL_GREEN_SIZE, 6,
EGL10.EGL_BLUE_SIZE, 5, EGL10.EGL_BLUE_SIZE, 5,
EGL10.EGL_ALPHA_SIZE, 0, EGL10.EGL_ALPHA_SIZE, 0,
EGL10.EGL_DEPTH_SIZE, 0, EGL10.EGL_DEPTH_SIZE, 16,
// Requires that setEGLContextClientVersion(2) is called on the view. // Requires that setEGLContextClientVersion(2) is called on the view.
EGL10.EGL_RENDERABLE_TYPE, 4 /* EGL_OPENGL_ES2_BIT */, EGL10.EGL_RENDERABLE_TYPE, 4 /* EGL_OPENGL_ES2_BIT */,
// EGL10.EGL_SAMPLE_BUFFERS, 1 /* true */, // EGL10.EGL_SAMPLE_BUFFERS, 1 /* true */,
@ -50,7 +50,7 @@ public class GlConfigChooser implements GLSurfaceView.EGLConfigChooser {
EGL10.EGL_GREEN_SIZE, 6, EGL10.EGL_GREEN_SIZE, 6,
EGL10.EGL_BLUE_SIZE, 5, EGL10.EGL_BLUE_SIZE, 5,
EGL10.EGL_ALPHA_SIZE, 0, EGL10.EGL_ALPHA_SIZE, 0,
EGL10.EGL_DEPTH_SIZE, 0, EGL10.EGL_DEPTH_SIZE, 16,
EGL10.EGL_RENDERABLE_TYPE, 4 /* EGL_OPENGL_ES2_BIT */, EGL10.EGL_RENDERABLE_TYPE, 4 /* EGL_OPENGL_ES2_BIT */,
EGL10.EGL_STENCIL_SIZE, 4, EGL10.EGL_STENCIL_SIZE, 4,
EGL10.EGL_NONE }; EGL10.EGL_NONE };
@ -93,7 +93,10 @@ public class GlConfigChooser implements GLSurfaceView.EGLConfigChooser {
// // else // // else
// if (findConfigAttrib(egl, display, configs[i], EGL10.EGL_RED_SIZE, 0) == 5 // if (findConfigAttrib(egl, display, configs[i], EGL10.EGL_RED_SIZE, 0) == 5
// && // &&
// findConfigAttrib(egl, display, configs[i], EGL10.EGL_ALPHA_SIZE, 0) == 0) { // findConfigAttrib(egl, display, configs[i], EGL10.EGL_ALPHA_SIZE, 0) == 0
// // &&
// // findConfigAttrib(egl, display, configs[i], EGL10.EGL_DEPTH_SIZE, 0) == 16
// ) {
// index = i; // index = i;
// break; // break;
// } // }

View File

@ -92,9 +92,23 @@ public class Tag {
this.hashCodeValue = calculateHashCode(); this.hashCodeValue = calculateHashCode();
} }
/**
* @param key
* the key of the tag.
* @param value
* the value of the tag.
* @param intern
* true when string should be intern()alized.
*/
public Tag(String key, String value, boolean intern) { public Tag(String key, String value, boolean intern) {
if (intern) {
this.key = (key == null ? null : key.intern());
this.value = (value == null ? null : value.intern());
}
else {
this.key = (key == null ? null : key); this.key = (key == null ? null : key);
this.value = (value == null ? null : value); this.value = (value == null ? null : value);
}
this.hashCodeValue = calculateHashCode(); this.hashCodeValue = calculateHashCode();
} }

View File

@ -60,6 +60,8 @@ public class Tile {
*/ */
public final long pixelY; public final long pixelY;
public volatile boolean isCanceled;
/** /**
* @param tileX * @param tileX
* the X number of the tile. * the X number of the tile.

View File

@ -251,7 +251,7 @@ public class MapDatabase implements IMapDatabase {
@Override @Override
public String getMapProjection() { public String getMapProjection() {
return getMapFileInfo().projectionName; return "WSG84"; // getMapFileInfo().projectionName;
} }
/* /*
@ -883,14 +883,25 @@ public class MapDatabase implements IMapDatabase {
boolean featureWayDoubleDeltaEncoding = (featureByte & WAY_FEATURE_DOUBLE_DELTA_ENCODING) != 0; boolean featureWayDoubleDeltaEncoding = (featureByte & WAY_FEATURE_DOUBLE_DELTA_ENCODING) != 0;
// check if the way has a name // check if the way has a name
if ((featureByte & WAY_FEATURE_NAME) != 0) if ((featureByte & WAY_FEATURE_NAME) != 0) {
textPos[0] = mReadBuffer.readUnsignedInt(); textPos[0] = mReadBuffer.readUnsignedInt();
String str = mReadBuffer.readUTF8EncodedStringAt(stringOffset
+ textPos[0]);
if (changed) {
Tag[] tmp = tags;
tags = new Tag[tmp.length + 1];
System.arraycopy(tmp, 0, tags, 0, tmp.length);
}
tags[tags.length - 1] = new Tag("name", str, false);
}
else else
textPos[0] = -1; textPos[0] = -1;
// check if the way has a house number // check if the way has a house number
if ((featureByte & WAY_FEATURE_HOUSE_NUMBER) != 0) if ((featureByte & WAY_FEATURE_HOUSE_NUMBER) != 0) {
textPos[1] = mReadBuffer.readUnsignedInt(); textPos[1] = mReadBuffer.readUnsignedInt();
}
else else
textPos[1] = -1; textPos[1] = -1;

View File

@ -19,10 +19,10 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.SocketException; import java.net.SocketException;
import java.net.SocketTimeoutException; import java.net.SocketTimeoutException;
import java.util.HashMap; import java.util.Collections;
import java.util.zip.GZIPInputStream; import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.http.Header;
import org.apache.http.HttpEntity; import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus; import org.apache.http.HttpStatus;
@ -33,7 +33,6 @@ import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme; import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry; import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicHeader;
import org.apache.http.params.BasicHttpParams; import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams; import org.apache.http.params.HttpParams;
@ -41,7 +40,6 @@ import org.mapsforge.core.BoundingBox;
import org.mapsforge.core.GeoPoint; import org.mapsforge.core.GeoPoint;
import org.mapsforge.core.Tag; import org.mapsforge.core.Tag;
import org.mapsforge.core.Tile; import org.mapsforge.core.Tile;
import org.mapsforge.core.WebMercator;
import org.mapsforge.database.FileOpenResult; import org.mapsforge.database.FileOpenResult;
import org.mapsforge.database.IMapDatabase; import org.mapsforge.database.IMapDatabase;
import org.mapsforge.database.IMapDatabaseCallback; import org.mapsforge.database.IMapDatabaseCallback;
@ -60,45 +58,62 @@ public class MapDatabase implements IMapDatabase {
private static final MapFileInfo mMapInfo = private static final MapFileInfo mMapInfo =
new MapFileInfo(new BoundingBox(-180, -90, 180, 90), new MapFileInfo(new BoundingBox(-180, -90, 180, 90),
new Byte((byte) 4), new GeoPoint(53.11, 8.85), new Byte((byte) 4), new GeoPoint(53.11, 8.85),
WebMercator.NAME, 0, 0, 0, "de", "comment", "author"); null, 0, 0, 0, "de", "comment", "author");
private boolean mOpenFile = false; private boolean mOpenFile = false;
// private static final String URL = "http://city.informatik.uni-bremen.de:8020/test/%d/%d/%d.osmtile"; // private static final String URL = "http://city.informatik.uni-bremen.de:8020/test/%d/%d/%d.osmtile";
private static final String URL = "http://city.informatik.uni-bremen.de/osmstache/test/%d/%d/%d.osmtile"; private static final String URL = "http://city.informatik.uni-bremen.de/osmstache/test/%d/%d/%d.osmtile";
// private static final String URL = "http://city.informatik.uni-bremen.de/osmstache/gis2/%d/%d/%d.osmtile"; // private static final String URL = "http://city.informatik.uni-bremen.de/osmstache/gis2/%d/%d/%d.osmtile";
private static final Header encodingHeader = // private static final Header encodingHeader =
new BasicHeader("Accept-Encoding", "gzip"); // new BasicHeader("Accept-Encoding", "gzip");
private static volatile HashMap<String, Tag> tagHash = new HashMap<String, Tag>(100); private static final int MAX_TAGS_CACHE = 100;
private static Map<String, Tag> tagHash = Collections
.synchronizedMap(new LinkedHashMap<String, Tag>(
MAX_TAGS_CACHE, 0.75f, true) {
private Tag[] curTags = new Tag[250]; private static final long serialVersionUID = 1L;
@Override
protected boolean removeEldestEntry(Entry<String, Tag> e) {
if (size() < MAX_TAGS_CACHE)
return false;
// Log.d(TAG, "cache: drop " + e.getValue());
return true;
}
});
private final static float REF_TILE_SIZE = 4096.0f;
private int MAX_TILE_TAGS = 100;
private Tag[] curTags = new Tag[MAX_TILE_TAGS];
private int mCurTagCnt; private int mCurTagCnt;
private HttpClient mClient; private HttpClient mClient;
private IMapDatabaseCallback mMapGenerator; private IMapDatabaseCallback mMapGenerator;
private float mScaleFactor; private float mScaleFactor;
private HttpGet mRequest = null; private HttpGet mRequest = null;
private Tile mTile;
@Override @Override
public QueryResult executeQuery(Tile tile, IMapDatabaseCallback mapDatabaseCallback) { public QueryResult executeQuery(Tile tile, IMapDatabaseCallback mapDatabaseCallback) {
mCanceled = false; mCanceled = false;
// just used for debugging ....
mTile = tile;
// Log.d(TAG, "get tile >> : " + tile); // Log.d(TAG, "get tile >> : " + tile);
String url = String.format(URL, Integer.valueOf(tile.zoomLevel), String url = String.format(URL, Integer.valueOf(tile.zoomLevel),
Long.valueOf(tile.tileX), Long.valueOf(tile.tileY)); Long.valueOf(tile.tileX), Long.valueOf(tile.tileY));
HttpGet getRequest = new HttpGet(url); HttpGet getRequest = new HttpGet(url);
getRequest.addHeader(encodingHeader);
mRequest = getRequest; mRequest = getRequest;
mMapGenerator = mapDatabaseCallback; mMapGenerator = mapDatabaseCallback;
mCurTagCnt = 0; mCurTagCnt = 0;
// using variable coordinate scalefactor to take advantage of varint mScaleFactor = REF_TILE_SIZE / Tile.TILE_SIZE;
mScaleFactor = 1 / 100f;
if (tile.zoomLevel < 12)
mScaleFactor = (float) Math.pow(2, (12 - tile.zoomLevel)) / 100f;
try { try {
HttpResponse response = mClient.execute(getRequest); HttpResponse response = mClient.execute(getRequest);
@ -110,17 +125,24 @@ public class MapDatabase implements IMapDatabase {
entity.consumeContent(); entity.consumeContent();
return QueryResult.FAILED; return QueryResult.FAILED;
} }
if (mTile.isCanceled) {
Log.d(TAG, "1 loading canceled " + mTile);
entity.consumeContent();
return QueryResult.FAILED;
}
InputStream is = null; InputStream is = null;
GZIPInputStream zis = null; // GZIPInputStream zis = null;
try { try {
is = entity.getContent(); is = entity.getContent();
zis = new GZIPInputStream(is); // zis = new GZIPInputStream(is);
decode(zis); decode(is);
} finally { } finally {
if (zis != null) // if (zis != null)
zis.close(); // zis.close();
if (is != null) if (is != null)
is.close(); is.close();
entity.consumeContent(); entity.consumeContent();
@ -137,6 +159,12 @@ public class MapDatabase implements IMapDatabase {
return QueryResult.FAILED; return QueryResult.FAILED;
} }
mRequest = null; mRequest = null;
if (mTile.isCanceled) {
Log.d(TAG, "2 loading canceled " + mTile);
return QueryResult.FAILED;
}
// Log.d(TAG, "get tile << : " + tile); // Log.d(TAG, "get tile << : " + tile);
return QueryResult.SUCCESS; return QueryResult.SUCCESS;
@ -144,7 +172,7 @@ public class MapDatabase implements IMapDatabase {
@Override @Override
public String getMapProjection() { public String getMapProjection() {
return WebMercator.NAME; return null;
} }
@Override @Override
@ -158,8 +186,6 @@ public class MapDatabase implements IMapDatabase {
} }
private void createClient() { private void createClient() {
// mClient = AndroidHttpClient.newInstance("Android");
mOpenFile = true; mOpenFile = true;
HttpParams params = new BasicHttpParams(); HttpParams params = new BasicHttpParams();
HttpConnectionParams.setStaleCheckingEnabled(params, false); HttpConnectionParams.setStaleCheckingEnabled(params, false);
@ -193,7 +219,8 @@ public class MapDatabase implements IMapDatabase {
return null; return null;
} }
private static final int BUFFER_SIZE = 65536 * 2; // // // hand sewed tile protocol buffers decoder // // //
private static final int BUFFER_SIZE = 65536;
private final byte[] buffer = new byte[BUFFER_SIZE]; private final byte[] buffer = new byte[BUFFER_SIZE];
private int bufferPos; private int bufferPos;
@ -261,20 +288,25 @@ public class MapDatabase implements IMapDatabase {
String tagString = decodeString(); String tagString = decodeString();
Tag tag = tagHash.get(tagString); Tag tag = tagHash.get(tagString);
if (tag == null) { if (tag == null) {
// Log.d(TAG, "tag:" + tagString); if (tagString.startsWith(Tag.TAG_KEY_NAME))
if (tagString.equals("name=")) tag = new Tag(Tag.TAG_KEY_NAME, tagString.substring(5), false);
tag = new Tag(tagString, false);
else else
tag = new Tag(tagString); tag = new Tag(tagString);
tagHash.put(tagString, tag); tagHash.put(tagString, tag);
} }
// FIXME ... // FIXME ...
if (mCurTagCnt < 250) if (mCurTagCnt >= MAX_TILE_TAGS) {
MAX_TILE_TAGS = mCurTagCnt + 10;
Tag[] tmp = new Tag[MAX_TILE_TAGS];
System.arraycopy(curTags, 0, tmp, 0, mCurTagCnt);
curTags = tmp;
}
curTags[mCurTagCnt++] = tag; curTags[mCurTagCnt++] = tag;
//
return true; return true;
} }
@ -285,7 +317,7 @@ public class MapDatabase implements IMapDatabase {
int indexCnt = 0; int indexCnt = 0;
int tagCnt = 0; int tagCnt = 0;
int coordCnt = 0; int coordCnt = 0;
int layer = 0; int layer = 5;
Tag[] tags = null; Tag[] tags = null;
short[] index = null; short[] index = null;
@ -294,7 +326,6 @@ public class MapDatabase implements IMapDatabase {
while (bytesRead < end) { while (bytesRead < end) {
// read tag and wire type // read tag and wire type
int val = decodeVarint32(); int val = decodeVarint32();
if (val == 0) if (val == 0)
break; break;
@ -350,18 +381,10 @@ public class MapDatabase implements IMapDatabase {
} }
float[] coords = tmpCoords; float[] coords = tmpCoords;
int pos = 0;
float z = mScaleFactor; // FIXME !!!!!
for (int j = 0, m = indexCnt; j < m; j++) { if (layer == 0)
float lastX = 0; layer = 5;
float lastY = 0;
for (int n = index[j] + pos; pos < n; pos += 2) {
lastX = coords[pos] = (coords[pos] * z) + lastX;
lastY = coords[pos + 1] = (coords[pos + 1] * z) + lastY;
}
}
mMapGenerator.renderWay((byte) layer, tags, coords, index, polygon); mMapGenerator.renderWay((byte) layer, tags, coords, index, polygon);
return true; return true;
@ -429,12 +452,20 @@ public class MapDatabase implements IMapDatabase {
readBuffer(bytes); readBuffer(bytes);
int cnt = 0; int cnt = 0;
int end = bufferPos + bytes; int end = bufferPos + bytes;
float scale = mScaleFactor;
// read repeated sint32 // read repeated sint32
int lastX = 0;
int lastY = 0;
while (bufferPos < end && cnt < numNodes) { while (bufferPos < end && cnt < numNodes) {
float lon = decodeZigZag32(decodeVarint32()) * mScaleFactor; int lon = decodeZigZag32(decodeVarint32()); // * mScaleFactor;
float lat = decodeZigZag32(decodeVarint32()) * mScaleFactor; int lat = decodeZigZag32(decodeVarint32()); // * mScaleFactor;
mMapGenerator.renderPointOfInterest(layer, lat, lon, tags); lastX = lon + lastX;
lastY = lat + lastY;
mMapGenerator.renderPointOfInterest(layer,
lastY / scale,
lastX / scale,
tags);
cnt += 2; cnt += 2;
} }
return cnt; return cnt;
@ -443,13 +474,6 @@ public class MapDatabase implements IMapDatabase {
private int MAX_WAY_COORDS = 32768; private int MAX_WAY_COORDS = 32768;
private float[] tmpCoords = new float[MAX_WAY_COORDS]; private float[] tmpCoords = new float[MAX_WAY_COORDS];
// private boolean ensureBufferSize(int size) throws IOException {
// if (size > (bufferSize - bufferPos))
// readBuffer(size - (bufferSize - bufferPos));
//
// return true;
// }
private Tag[] decodeWayTags(int tagCnt) throws IOException { private Tag[] decodeWayTags(int tagCnt) throws IOException {
int bytes = decodeVarint32(); int bytes = decodeVarint32();
@ -457,33 +481,45 @@ public class MapDatabase implements IMapDatabase {
int cnt = 0; int cnt = 0;
int end = bytesRead + bytes; int end = bytesRead + bytes;
int max = curTags.length; int max = mCurTagCnt;
while (bytesRead < end) { while (bytesRead < end) {
int tagNum = decodeVarint32(); int tagNum = decodeVarint32();
if (tagNum < 0 || cnt == tagCnt) if (tagNum < 0 || cnt == tagCnt) {
continue; Log.d(TAG, "NULL TAG: " + mTile + " invalid tag:" + tagNum + " "
+ tagCnt + "/" + cnt);
break;
}
if (tagNum < Tags.MAX) if (tagNum < Tags.MAX)
tags[cnt++] = Tags.tags[tagNum]; tags[cnt++] = Tags.tags[tagNum];
else { else {
tagNum -= Tags.LIMIT; tagNum -= Tags.LIMIT;
if (tagNum >= 0 && tagNum < max) { if (tagNum >= 0 && tagNum < max) {
// Log.d(TAG, "variable tag: " + curTags[tagNum]); // Log.d(TAG, "variable tag: " + curTags[tagNum]);
tags[cnt++] = curTags[tagNum]; tags[cnt++] = curTags[tagNum];
} else {
Log.d(TAG, "NULL TAG: " + mTile + " could find tag:" + tagNum + " "
+ tagCnt + "/" + cnt);
} }
} }
// else DEBUG...
} }
if (tagCnt != cnt)
Log.d(TAG, "NULL TAG: " + mTile + " ...");
return tags; return tags;
} }
private short[] mIndices = new short[10];
private short[] decodeWayIndices(int indexCnt) throws IOException { private short[] decodeWayIndices(int indexCnt) throws IOException {
int bytes = decodeVarint32(); int bytes = decodeVarint32();
short[] index = new short[indexCnt]; short[] index = mIndices;
if (index.length < indexCnt + 1) {
index = mIndices = new short[indexCnt + 1];
}
int cnt = 0; int cnt = 0;
int end = bytesRead + bytes; int end = bytesRead + bytes;
@ -495,6 +531,9 @@ public class MapDatabase implements IMapDatabase {
// else DEBUG... // else DEBUG...
} }
index[indexCnt] = -1;
return index; return index;
} }
@ -514,67 +553,78 @@ public class MapDatabase implements IMapDatabase {
int cnt = 0; int cnt = 0;
int result; int result;
int x, lastX = 0;
int y, lastY = 0;
boolean even = true;
float scale = mScaleFactor;
// read repeated sint32 // read repeated sint32
while (pos < end) { while (pos < end) {
if (cnt >= MAX_WAY_COORDS) { if (cnt >= MAX_WAY_COORDS) {
Log.d(TAG, "increase way coord buffer " + mTile);
MAX_WAY_COORDS += 128; MAX_WAY_COORDS += 128;
float[] tmp = new float[MAX_WAY_COORDS]; float[] tmp = new float[MAX_WAY_COORDS];
System.arraycopy(coords, 0, tmp, 0, cnt); System.arraycopy(coords, 0, tmp, 0, cnt);
tmpCoords = coords = tmp; tmpCoords = coords = tmp;
} }
byte tmp = buf[pos++]; if (buf[pos] >= 0) {
if (tmp >= 0) { result = buf[pos++];
result = tmp; } else if (buf[pos + 1] >= 0) {
result = buf[pos] & 0x7f
| buf[pos + 1] << 7;
pos += 2;
} else if (buf[pos + 2] >= 0) {
result = buf[pos] & 0x7f
| buf[pos + 1] << 7
| buf[pos + 2] << 14;
pos += 3;
} else if (buf[pos + 3] >= 0) {
result = buf[pos] & 0x7f
| buf[pos + 1] << 7
| buf[pos + 2] << 14
| buf[pos + 3] << 21;
pos += 4;
Log.d(TAG, "4 Stuffs too large " + mTile);
} else { } else {
result = tmp & 0x7f; result = buf[pos] & 0x7f
if ((tmp = buf[pos++]) >= 0) { | buf[pos + 1] << 7
result |= tmp << 7; | buf[pos + 2] << 14
} else { | buf[pos + 3] << 21
result |= (tmp & 0x7f) << 7; | buf[pos + 4] << 28;
if ((tmp = buf[pos++]) >= 0) { pos += 5;
result |= tmp << 14;
} else {
result |= (tmp & 0x7f) << 14;
if ((tmp = buf[pos++]) >= 0) {
result |= tmp << 21;
} else {
result |= (tmp & 0x7f) << 21;
result |= (tmp = buf[pos++]) << 28;
if (tmp < 0) { Log.d(TAG, "5 Stuffs too large " + mTile);
if (buf[pos + 4] < 0) {
Log.d(TAG, "Stuffs too large ...");
int i = 0; int i = 0;
// Discard upper 32 bits.
while (i++ < 5) { while (i++ < 5) {
if (buf[pos++] >= 0) if (buf[pos++] >= 0)
break; break;
} }
if (i == 5) if (i == 5)
// FIXME throw some poo throw new IOException("EEEK malformed varInt");
Log.d(TAG, "EEK malformedVarint");
} }
} }
if (even) {
x = ((result >>> 1) ^ -(result & 1));
lastX = lastX + x;
coords[cnt++] = lastX / scale;
even = false;
} else {
y = ((result >>> 1) ^ -(result & 1));
lastY = lastY + y;
coords[cnt++] = lastY / scale;
even = true;
} }
} }
}
coords[cnt++] = (result >>> 1) ^ -(result & 1);
}
bufferPos = pos; bufferPos = pos;
bytesRead += bytes; bytesRead += bytes;
// while (bytesRead < end) {
// int val = decodeZigZag32(decodeVarint32());
// if (cnt >= MAX_WAY_COORDS) {
// MAX_WAY_COORDS += 128;
// Log.d(TAG, "increase coords array " + MAX_WAY_COORDS);
// float[] tmp = new float[MAX_WAY_COORDS];
// System.arraycopy(tmpCoords, 0, tmp, 0, cnt);
// tmpCoords = tmp;
// }
// tmpCoords[cnt++] = val;
// }
return cnt; return cnt;
} }
@ -589,9 +639,6 @@ public class MapDatabase implements IMapDatabase {
} }
bufferSize = len; bufferSize = len;
bufferPos = 0; bufferPos = 0;
// Log.d(TAG, "pos " + bufferPos + ", size " + bufferSize + ", read "
// + bytesRead);
} }
private void readBuffer(int size) throws IOException { private void readBuffer(int size) throws IOException {
@ -612,6 +659,10 @@ public class MapDatabase implements IMapDatabase {
} }
while ((bufferSize - bufferPos) < size) { while ((bufferSize - bufferPos) < size) {
if (mTile.isCanceled) {
throw new IOException("canceled " + mTile);
}
// read until requested size is available in buffer // read until requested size is available in buffer
int len = inputStream.read(buffer, bufferSize, BUFFER_SIZE - bufferSize); int len = inputStream.read(buffer, bufferSize, BUFFER_SIZE - bufferSize);
if (len < 0) { if (len < 0) {
@ -621,13 +672,6 @@ public class MapDatabase implements IMapDatabase {
bufferSize += len; bufferSize += len;
// if (len == 0)
// try {
// wait(50);
// } catch (InterruptedException e) {
// // just waiting for data
// }
if (mCanceled) if (mCanceled)
throw new IOException("... canceld?"); throw new IOException("... canceld?");
} }
@ -637,6 +681,17 @@ public class MapDatabase implements IMapDatabase {
// + ", read " + bytesRead); // + ", read " + bytesRead);
} }
private boolean mCanceled;
@Override
public void cancel() {
mCanceled = true;
if (mRequest != null) {
mRequest.abort();
mRequest = null;
}
}
/* All code below is taken from or based on Google's Protocol Buffers implementation: */ /* All code below is taken from or based on Google's Protocol Buffers implementation: */
// Protocol Buffers - Google's data interchange format // Protocol Buffers - Google's data interchange format
@ -727,17 +782,4 @@ public class MapDatabase implements IMapDatabase {
return (n >>> 1) ^ -(n & 1); return (n >>> 1) ^ -(n & 1);
} }
private boolean mCanceled;
@Override
public void cancel() {
mCanceled = true;
if (mRequest != null) {
mRequest.abort();
mRequest = null;
}
// mClient.getConnectionManager().shutdown();
// mClient = null;
}
} }

View File

@ -45,14 +45,14 @@ import android.util.Log;
public class MapDatabase implements IMapDatabase { public class MapDatabase implements IMapDatabase {
private final static String TAG = "MapDatabase"; private final static String TAG = "MapDatabase";
private static final String QUERY = "SELECT tags, geom FROM __get_tile(?,?,?)"; private static final String QUERY = "SELECT tags, geom FROM __get_tile(?,?,?,false)";
private final float mScale = 1; // 1000000.0f; private final float mScale = 1;
private int mCoordPos = 0; private int mCoordPos = 0;
private int mIndexPos = 0; private int mIndexPos = 0;
private float[] mCoords = new float[100000]; private float[] mCoords;
private short[] mIndex = new short[10000]; private short[] mIndex;
private Tag[] mTags; private Tag[] mTags;
@ -71,7 +71,7 @@ public class MapDatabase implements IMapDatabase {
private boolean connect() { private boolean connect() {
Connection conn = null; Connection conn = null;
String dburl = "jdbc:postgresql://city.informatik.uni-bremen.de:5432/gis-2.0"; String dburl = "jdbc:postgresql://city.informatik.uni-bremen.de:5432/gis";
Properties dbOpts = new Properties(); Properties dbOpts = new Properties();
dbOpts.setProperty("user", "osm"); dbOpts.setProperty("user", "osm");
@ -212,6 +212,10 @@ public class MapDatabase implements IMapDatabase {
@Override @Override
public FileOpenResult openFile(File mapFile) { public FileOpenResult openFile(File mapFile) {
mOpenFile = true; mOpenFile = true;
if (mCoords == null) {
mCoords = new float[100000];
mIndex = new short[100000];
}
return new FileOpenResult(); return new FileOpenResult();
} }
@ -226,6 +230,8 @@ public class MapDatabase implements IMapDatabase {
connection = null; connection = null;
} }
} }
mCoords = null;
mIndex = null;
mOpenFile = false; mOpenFile = false;
} }