- 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:
parent
1cf0c02dd2
commit
2fccf0f214
@ -16,6 +16,7 @@ package org.mapsforge.android;
|
||||
|
||||
import org.mapsforge.android.mapgenerator.IMapGenerator;
|
||||
import org.mapsforge.android.mapgenerator.MapGeneratorJob;
|
||||
import org.mapsforge.android.rendertheme.RenderTheme;
|
||||
|
||||
import android.opengl.GLSurfaceView;
|
||||
|
||||
@ -46,4 +47,6 @@ public interface IMapRenderer extends GLSurfaceView.Renderer {
|
||||
public void redrawTiles(boolean clear);
|
||||
|
||||
public IMapGenerator createMapGenerator();
|
||||
|
||||
public void setRenderTheme(RenderTheme t);
|
||||
}
|
||||
|
||||
@ -496,6 +496,7 @@ public class MapView extends GLSurfaceView {
|
||||
*
|
||||
* @param internalRenderTheme
|
||||
* the internal rendering theme.
|
||||
* @return ...
|
||||
* @throws IllegalArgumentException
|
||||
* if the supplied internalRenderTheme is null.
|
||||
*/
|
||||
@ -538,6 +539,7 @@ public class MapView extends GLSurfaceView {
|
||||
try {
|
||||
inputStream = theme.getRenderThemeAsStream();
|
||||
RenderTheme t = RenderThemeHandler.getRenderTheme(inputStream);
|
||||
mMapRenderer.setRenderTheme(t);
|
||||
mMapWorkers[0].getMapGenerator().setRenderTheme(t);
|
||||
return true;
|
||||
} catch (ParserConfigurationException e) {
|
||||
|
||||
@ -14,21 +14,23 @@
|
||||
*/
|
||||
package org.mapsforge.android.glrenderer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.mapsforge.android.mapgenerator.MapTile;
|
||||
import org.mapsforge.core.Tile;
|
||||
|
||||
class GLMapTile extends MapTile {
|
||||
long lastDraw = 0;
|
||||
|
||||
VertexBufferObject vbo;
|
||||
|
||||
// polygonOffset is always 8
|
||||
int lineOffset;
|
||||
|
||||
VertexBufferObject lineVBO;
|
||||
VertexBufferObject polygonVBO;
|
||||
TextTexture texture;
|
||||
|
||||
LineLayer lineLayers;
|
||||
PolygonLayer polygonLayers;
|
||||
|
||||
ArrayList<TextItem> labels;
|
||||
TextItem labels;
|
||||
|
||||
boolean newData;
|
||||
boolean loading;
|
||||
@ -37,9 +39,6 @@ class GLMapTile extends MapTile {
|
||||
final long x;
|
||||
final long y;
|
||||
|
||||
// scissor coordinates
|
||||
int sx, sy, sw, sh;
|
||||
|
||||
final GLMapTile[] child = { null, null, null, null };
|
||||
GLMapTile parent;
|
||||
|
||||
|
||||
@ -15,38 +15,35 @@
|
||||
package org.mapsforge.android.glrenderer;
|
||||
|
||||
import org.mapsforge.android.rendertheme.renderinstruction.Line;
|
||||
import org.mapsforge.core.Tile;
|
||||
|
||||
import android.graphics.Paint.Cap;
|
||||
import android.util.FloatMath;
|
||||
|
||||
class LineLayer {
|
||||
|
||||
private static final float SCALE_FACTOR = 16;
|
||||
|
||||
Line line;
|
||||
private static final float S = MapRenderer.COORD_MULTIPLIER;
|
||||
private static final float S1000 = 1000;
|
||||
|
||||
LineLayer next;
|
||||
LineLayer outlines;
|
||||
|
||||
Line line;
|
||||
float width;
|
||||
boolean isOutline;
|
||||
int layer;
|
||||
|
||||
ShortItem pool;
|
||||
protected ShortItem curItem;
|
||||
int verticesCnt;
|
||||
int offset;
|
||||
short[] mVertex;
|
||||
|
||||
final int layer;
|
||||
|
||||
LineLayer(int layer, Line line, boolean outline) {
|
||||
LineLayer(int layer, Line line, float width, boolean outline) {
|
||||
this.layer = layer;
|
||||
|
||||
this.width = width;
|
||||
this.line = line;
|
||||
this.isOutline = outline;
|
||||
|
||||
if (!outline) {
|
||||
curItem = ShortPool.get();
|
||||
pool = curItem;
|
||||
}
|
||||
}
|
||||
|
||||
void addOutline(LineLayer link) {
|
||||
@ -58,45 +55,82 @@ class LineLayer {
|
||||
outlines = link;
|
||||
}
|
||||
|
||||
short[] getNextItem() {
|
||||
curItem.used = ShortItem.SIZE;
|
||||
private static ShortItem addTwoVertex(short[] vertex, ShortItem item) {
|
||||
ShortItem it = item;
|
||||
|
||||
curItem.next = ShortPool.get();
|
||||
curItem = curItem.next;
|
||||
if (it.used + 6 >= ShortItem.SIZE) {
|
||||
|
||||
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 a;
|
||||
int pointPos = pos;
|
||||
boolean rounded = capRound;
|
||||
width = w;// * SCALE_FACTOR;
|
||||
if (w < 0.5)
|
||||
rounded = false;
|
||||
boolean rounded = false;
|
||||
boolean squared = 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
|
||||
verticesCnt += length + (rounded ? 6 : 2);
|
||||
|
||||
int MAX = PoolItem.SIZE;
|
||||
ShortItem si = curItem;
|
||||
|
||||
short[] curVertices = curItem.vertices;
|
||||
int vertexPos = curItem.used;
|
||||
x = pointArray[pointPos++];
|
||||
y = pointArray[pointPos++];
|
||||
|
||||
if (vertexPos == MAX) {
|
||||
curVertices = getNextItem();
|
||||
vertexPos = 0;
|
||||
}
|
||||
|
||||
x = pointArray[pointPos++];// * SCALE_FACTOR;
|
||||
y = pointArray[pointPos++];// * SCALE_FACTOR;
|
||||
|
||||
nextX = pointArray[pointPos++];// * SCALE_FACTOR;
|
||||
nextY = pointArray[pointPos++];// * SCALE_FACTOR;
|
||||
nextX = pointArray[pointPos++];
|
||||
nextY = pointArray[pointPos++];
|
||||
|
||||
// Calculate triangle corners for the given width
|
||||
vx = nextX - x;
|
||||
@ -110,109 +144,83 @@ class LineLayer {
|
||||
ux = -vy;
|
||||
uy = vx;
|
||||
|
||||
float uxw = ux * w;
|
||||
float uyw = uy * w;
|
||||
float uxw = ux;
|
||||
float uyw = uy;
|
||||
|
||||
float vxw = vx * w;
|
||||
float vyw = vy * w;
|
||||
float vxw = vx;
|
||||
float vyw = vy;
|
||||
int tsize = Tile.TILE_SIZE;
|
||||
|
||||
// boolean outside = (x <= 0 || x >= Tile.TILE_SIZE || y <= 0 || y >= Tile.TILE_SIZE)
|
||||
// && (x - vxw <= 0 || x - vxw >= Tile.TILE_SIZE || y - vyw <= 0 || y - vyw >= Tile.TILE_SIZE);
|
||||
short v[] = mVertex;
|
||||
|
||||
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) {
|
||||
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
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
v[2] = (short) (-(uxw + vxw) * S1000);
|
||||
v[3] = (short) (-(uyw + vyw) * S1000);
|
||||
v[4] = 1;
|
||||
v[5] = 1;
|
||||
si = addVertex(v, si);
|
||||
|
||||
// Start of line
|
||||
curVertices[vertexPos++] = (short) ((x + uxw) * SCALE_FACTOR);
|
||||
curVertices[vertexPos++] = (short) ((y + uyw) * SCALE_FACTOR);
|
||||
curVertices[vertexPos++] = -1;
|
||||
curVertices[vertexPos++] = 0;
|
||||
v[2] = (short) ((uxw) * S1000);
|
||||
v[3] = (short) ((uyw) * S1000);
|
||||
v[4] = -1;
|
||||
v[5] = 0;
|
||||
si = addVertex(v, si);
|
||||
|
||||
if (vertexPos == MAX) {
|
||||
curVertices = getNextItem();
|
||||
vertexPos = 0;
|
||||
}
|
||||
|
||||
curVertices[vertexPos++] = (short) ((x - uxw) * SCALE_FACTOR);
|
||||
curVertices[vertexPos++] = (short) ((y - uyw) * SCALE_FACTOR);
|
||||
curVertices[vertexPos++] = 1;
|
||||
curVertices[vertexPos++] = 0;
|
||||
v[2] = (short) ((-uxw) * S1000);
|
||||
v[3] = (short) ((-uyw) * S1000);
|
||||
v[4] = 1;
|
||||
v[5] = 0;
|
||||
si = addVertex(v, si);
|
||||
|
||||
} else {
|
||||
// outside means line is probably clipped
|
||||
// TODO should align ending with tile boundary
|
||||
// for now, just extend the line a little
|
||||
if (!outside) {
|
||||
|
||||
if (squared) {
|
||||
vxw = 0;
|
||||
vyw = 0;
|
||||
} else if (!outside) {
|
||||
vxw *= 0.5;
|
||||
vyw *= 0.5;
|
||||
}
|
||||
if (rounded) {
|
||||
|
||||
if (rounded)
|
||||
verticesCnt -= 2;
|
||||
}
|
||||
|
||||
// Add the first point 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;
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
v[2] = (short) (-(uxw + vxw) * S1000);
|
||||
v[3] = (short) (-(uyw + vyw) * S1000);
|
||||
v[4] = 1;
|
||||
v[5] = 0;
|
||||
si = addVertex(v, si);
|
||||
}
|
||||
|
||||
prevX = x;
|
||||
prevY = y;
|
||||
x = nextX;
|
||||
y = nextY;
|
||||
// boolean flipped = false;
|
||||
|
||||
for (; pointPos < pos + length;) {
|
||||
nextX = pointArray[pointPos++];
|
||||
@ -235,58 +243,40 @@ class LineLayer {
|
||||
// Sum of these two vectors points
|
||||
ux = vx + wx;
|
||||
uy = vy + wy;
|
||||
|
||||
a = -wy * ux + wx * uy;
|
||||
|
||||
if ((a < 0.1 && a > -0.1)) {
|
||||
// Almost straight, use normal vector
|
||||
// boolean split = false;
|
||||
if (a < 0.1f && a > -0.1f) {
|
||||
// Almost straight or miter goes to infinity, use normal vector
|
||||
ux = -wy;
|
||||
uy = wx;
|
||||
} else {
|
||||
ux = (ux / 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;
|
||||
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;
|
||||
uyw = uy * w;
|
||||
uxw = ux * S1000;
|
||||
uyw = uy * S1000;
|
||||
|
||||
if (vertexPos == MAX) {
|
||||
curVertices = getNextItem();
|
||||
vertexPos = 0;
|
||||
}
|
||||
v[6] = v[0] = (short) (x * S);
|
||||
v[7] = v[1] = (short) (y * S);
|
||||
|
||||
curVertices[vertexPos++] = (short) ((x + uxw) * SCALE_FACTOR);
|
||||
curVertices[vertexPos++] = (short) ((y + uyw) * SCALE_FACTOR);
|
||||
curVertices[vertexPos++] = -1;
|
||||
curVertices[vertexPos++] = 0;
|
||||
v[2] = (short) uxw;
|
||||
v[3] = (short) uyw;
|
||||
v[4] = -1;
|
||||
v[5] = 0;
|
||||
|
||||
if (vertexPos == MAX) {
|
||||
curVertices = getNextItem();
|
||||
vertexPos = 0;
|
||||
}
|
||||
|
||||
curVertices[vertexPos++] = (short) ((x - uxw) * SCALE_FACTOR);
|
||||
curVertices[vertexPos++] = (short) ((y - uyw) * SCALE_FACTOR);
|
||||
curVertices[vertexPos++] = 1;
|
||||
curVertices[vertexPos++] = 0;
|
||||
v[8] = (short) -uxw;
|
||||
v[9] = (short) -uyw;
|
||||
v[10] = 1;
|
||||
v[11] = 0;
|
||||
si = addTwoVertex(v, si);
|
||||
|
||||
prevX = x;
|
||||
prevY = y;
|
||||
@ -305,105 +295,71 @@ class LineLayer {
|
||||
ux = vy;
|
||||
uy = -vx;
|
||||
|
||||
uxw = ux * w;
|
||||
uyw = uy * w;
|
||||
uxw = ux;
|
||||
uyw = uy;
|
||||
|
||||
vxw = vx * w;
|
||||
vyw = vy * w;
|
||||
vxw = vx;
|
||||
vyw = vy;
|
||||
|
||||
// outside = (x <= 0 || x >= Tile.TILE_SIZE || y <= 0 || y >= Tile.TILE_SIZE)
|
||||
// && (x - vxw <= 0 || x - vxw >= Tile.TILE_SIZE || y - vyw <= 0 || y - vyw >= Tile.TILE_SIZE);
|
||||
outside = (x <= 0 || x >= tsize || y <= 0 || y >= tsize)
|
||||
&& (x - vxw <= 0 || x - vxw >= tsize || y - vyw <= 0 || y - vyw >= tsize);
|
||||
|
||||
if (vertexPos == MAX) {
|
||||
curVertices = getNextItem();
|
||||
vertexPos = 0;
|
||||
}
|
||||
v[0] = (short) (x * S);
|
||||
v[1] = (short) (y * S);
|
||||
|
||||
if (rounded && !outside) {
|
||||
curVertices[vertexPos++] = (short) ((x + uxw) * SCALE_FACTOR);
|
||||
curVertices[vertexPos++] = (short) ((y + uyw) * SCALE_FACTOR);
|
||||
curVertices[vertexPos++] = -1;
|
||||
curVertices[vertexPos++] = 0;
|
||||
v[2] = (short) ((uxw) * S1000);
|
||||
v[3] = (short) ((uyw) * S1000);
|
||||
v[4] = -1;
|
||||
v[5] = 0;
|
||||
si = addVertex(v, si);
|
||||
|
||||
if (vertexPos == MAX) {
|
||||
curVertices = getNextItem();
|
||||
vertexPos = 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
v[2] = (short) ((-uxw) * S1000);
|
||||
v[3] = (short) ((-uyw) * S1000);
|
||||
v[4] = 1;
|
||||
v[5] = 0;
|
||||
si = addVertex(v, si);
|
||||
|
||||
// For rounded line edges
|
||||
curVertices[vertexPos++] = (short) ((x + uxw - vxw) * SCALE_FACTOR);
|
||||
curVertices[vertexPos++] = (short) ((y + uyw - vyw) * SCALE_FACTOR);
|
||||
curVertices[vertexPos++] = -1;
|
||||
curVertices[vertexPos++] = -1;
|
||||
v[2] = (short) ((uxw - vxw) * S1000);
|
||||
v[3] = (short) ((uyw - vyw) * S1000);
|
||||
v[4] = -1;
|
||||
v[5] = -1;
|
||||
si = addVertex(v, si);
|
||||
|
||||
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++] = -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;
|
||||
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);
|
||||
|
||||
} else {
|
||||
if (!outside) {
|
||||
if (squared) {
|
||||
vxw = 0;
|
||||
vyw = 0;
|
||||
} else if (!outside) {
|
||||
vxw *= 0.5;
|
||||
vyw *= 0.5;
|
||||
}
|
||||
if (rounded) {
|
||||
|
||||
if (rounded)
|
||||
verticesCnt -= 2;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
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);
|
||||
}
|
||||
|
||||
curItem.used = vertexPos;
|
||||
curItem = si;
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,136 +14,167 @@
|
||||
*/
|
||||
package org.mapsforge.android.glrenderer;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import static android.opengl.GLES20.GL_TRIANGLE_STRIP;
|
||||
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 org.mapsforge.android.rendertheme.renderinstruction.Line;
|
||||
import org.mapsforge.android.utils.GlUtils;
|
||||
|
||||
import android.opengl.GLES20;
|
||||
import android.util.FloatMath;
|
||||
|
||||
class LineLayers {
|
||||
private static int NUM_VERTEX_FLOATS = 4;
|
||||
private static int NUM_VERTEX_SHORTS = 6;
|
||||
|
||||
// static FloatBuffer compileLayerData(LineLayer layers, FloatBuffer buf) {
|
||||
// FloatBuffer fbuf = buf;
|
||||
// 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);
|
||||
// }
|
||||
// }
|
||||
private static final int LINE_VERTICES_DATA_POS_OFFSET = 0;
|
||||
private static final int LINE_VERTICES_DATA_TEX_OFFSET = 8;
|
||||
|
||||
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;
|
||||
ShortBuffer sbuf = buf;
|
||||
|
||||
for (LineLayer l = layers; l != null; l = l.next)
|
||||
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;
|
||||
|
||||
// short[] data = new short[PoolItem.SIZE];
|
||||
|
||||
ShortItem last = null, items = null;
|
||||
|
||||
for (LineLayer l = layers; l != null; l = l.next) {
|
||||
@ -151,8 +182,6 @@ class LineLayers {
|
||||
continue;
|
||||
|
||||
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);
|
||||
last = item;
|
||||
}
|
||||
@ -166,19 +195,110 @@ class LineLayers {
|
||||
}
|
||||
|
||||
l.pool = null;
|
||||
l.curItem = null;
|
||||
}
|
||||
|
||||
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) {
|
||||
for (LineLayer l = layer; l != null; l = l.next) {
|
||||
if (l.pool != null)
|
||||
if (l.pool != null) {
|
||||
ShortPool.add(l.pool);
|
||||
l.pool = null;
|
||||
l.curItem = null;
|
||||
}
|
||||
}
|
||||
// LineLayers.add(layer);
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,8 +14,6 @@
|
||||
*/
|
||||
package org.mapsforge.android.glrenderer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.mapsforge.android.mapgenerator.IMapGenerator;
|
||||
import org.mapsforge.android.mapgenerator.MapGeneratorJob;
|
||||
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.Caption;
|
||||
import org.mapsforge.android.rendertheme.renderinstruction.Line;
|
||||
import org.mapsforge.android.rendertheme.renderinstruction.PathText;
|
||||
import org.mapsforge.android.rendertheme.renderinstruction.RenderInstruction;
|
||||
import org.mapsforge.core.MercatorProjection;
|
||||
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 PIx4 = Math.PI * 4;
|
||||
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 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;
|
||||
|
||||
@ -66,14 +65,23 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
|
||||
private LineLayer mCurLineLayer;
|
||||
private PolygonLayer mCurPolyLayer;
|
||||
|
||||
private ArrayList<TextItem> mLabels;
|
||||
private TextItem mLabels;
|
||||
|
||||
private int mDrawingLayer;
|
||||
private int mLevels;
|
||||
|
||||
private boolean useSphericalMercator = false;
|
||||
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,53 +92,62 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
|
||||
private float mPoiX = 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 void filterTags(Tag[] tags) {
|
||||
for (int i = 0; i < tags.length; 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];
|
||||
tags[i] = mTagEmptyName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// private RenderInstruction[] mNodeRenderInstructions;
|
||||
|
||||
@Override
|
||||
public void renderPointOfInterest(byte layer, float latitude, float longitude,
|
||||
Tag[] tags) {
|
||||
|
||||
mTagName = null;
|
||||
|
||||
long x = mCurrentTile.x;
|
||||
long y = mCurrentTile.y;
|
||||
long z = Tile.TILE_SIZE << mCurrentTile.zoomLevel;
|
||||
if (mMapProjection != null)
|
||||
{
|
||||
long x = mCurrentTile.x;
|
||||
long y = mCurrentTile.y;
|
||||
long z = Tile.TILE_SIZE << mCurrentTile.zoomLevel;
|
||||
|
||||
double divx, divy;
|
||||
long dx = (x - (z >> 1));
|
||||
long dy = (y - (z >> 1));
|
||||
double divx, divy;
|
||||
long dx = (x - (z >> 1));
|
||||
long dy = (y - (z >> 1));
|
||||
|
||||
if (useSphericalMercator) {
|
||||
divx = f900913 / (z >> 1);
|
||||
divy = f900913 / (z >> 1);
|
||||
mPoiX = (float) (longitude / divx - dx);
|
||||
mPoiY = (float) (latitude / divy + dy);
|
||||
if (mMapProjection == WebMercator.NAME) {
|
||||
double div = f900913 / (z >> 1);
|
||||
// divy = f900913 / (z >> 1);
|
||||
mPoiX = (float) (longitude / div - dx);
|
||||
mPoiY = (float) (latitude / div + dy);
|
||||
} else {
|
||||
divx = 180000000.0 / (z >> 1);
|
||||
divy = z / PIx4;
|
||||
mPoiX = (float) (longitude / divx - dx);
|
||||
double sinLat = Math.sin(latitude * PI180);
|
||||
mPoiY = (float) (Math.log((1.0 + sinLat) / (1.0 - sinLat)) * divy + dy);
|
||||
if (mPoiX < -10 || mPoiX > Tile.TILE_SIZE + 10 || mPoiY < -10
|
||||
|| mPoiY > Tile.TILE_SIZE + 10)
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
divx = 180000000.0 / (z >> 1);
|
||||
divy = z / PIx4;
|
||||
mPoiX = (float) (longitude / divx - dx);
|
||||
double sinLat = Math.sin(latitude * PI180);
|
||||
mPoiY = (float) (Math.log((1.0 + sinLat) / (1.0 - sinLat)) * divy + dy);
|
||||
if (mPoiX < -10 || mPoiX > Tile.TILE_SIZE + 10 || mPoiY < -10
|
||||
|| mPoiY > Tile.TILE_SIZE + 10)
|
||||
return;
|
||||
mPoiX = longitude;
|
||||
mPoiY = latitude;
|
||||
}
|
||||
|
||||
// remove tags that should not be cached in Rendertheme
|
||||
filterTags(tags);
|
||||
// Log.d(TAG, "renderPointOfInterest: " + mTagName);
|
||||
|
||||
// mNodeRenderInstructions =
|
||||
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
|
||||
public void renderWay(byte layer, Tag[] tags, float[] wayNodes, short[] wayLength,
|
||||
boolean closed) {
|
||||
@ -239,6 +180,9 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
|
||||
mWayNodes = wayNodes;
|
||||
mWays = wayLength;
|
||||
|
||||
// remove tags that should not be cached in Rendertheme
|
||||
filterTags(tags);
|
||||
|
||||
// if (mRenderInstructions != null) {
|
||||
// for (int i = 0, n = mRenderInstructions.length; i < n; i++)
|
||||
// mRenderInstructions[i].renderWay(this, tags);
|
||||
@ -266,7 +210,6 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
|
||||
mRenderInstructions = MapGenerator.renderTheme.matchWay(this, debugTagWay,
|
||||
(byte) 0, true, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -277,9 +220,10 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
|
||||
return;
|
||||
|
||||
if (caption.textKey == mTagEmptyName.key) {
|
||||
if (mLabels == null)
|
||||
mLabels = new ArrayList<TextItem>();
|
||||
mLabels.add(new TextItem(mWayNodes[0], mWayNodes[1], mTagName.value, caption));
|
||||
|
||||
TextItem t = 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;
|
||||
|
||||
if (caption.textKey == mTagEmptyName.key) {
|
||||
if (mLabels == null)
|
||||
mLabels = new ArrayList<TextItem>();
|
||||
mLabels.add(new TextItem(mPoiX, mPoiY, mTagName.value, caption));
|
||||
TextItem t = new TextItem(mPoiX, mPoiY, mTagName.value, caption);
|
||||
t.next = mLabels;
|
||||
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;
|
||||
|
||||
@Override
|
||||
public void renderWay(Line line) {
|
||||
public void renderWay(Line line, int level) {
|
||||
|
||||
projectToTile();
|
||||
|
||||
LineLayer outlineLayer = null;
|
||||
if (line.outline && mCurLineLayer == null)
|
||||
return;
|
||||
|
||||
float w = line.width;
|
||||
|
||||
if (!line.fixed) {
|
||||
w *= mStrokeScale;
|
||||
w *= mProjectionScaleFactor;
|
||||
}
|
||||
|
||||
LineLayer lineLayer = null;
|
||||
|
||||
int numLayer = mDrawingLayer + line.level;
|
||||
int numLayer = mDrawingLayer + level;
|
||||
|
||||
LineLayer l = mLineLayers;
|
||||
|
||||
@ -334,7 +302,9 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
|
||||
lineLayer = mCurLineLayer;
|
||||
} else if (l == null || l.layer > numLayer) {
|
||||
// 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;
|
||||
mLineLayers = lineLayer;
|
||||
} else {
|
||||
@ -346,7 +316,8 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
|
||||
}
|
||||
// insert new layer between current and next layer
|
||||
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;
|
||||
l.next = lineLayer;
|
||||
}
|
||||
@ -357,77 +328,83 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
|
||||
if (lineLayer == null)
|
||||
return;
|
||||
|
||||
if (line.outline) {
|
||||
lineLayer.addOutline(mCurLineLayer);
|
||||
return;
|
||||
}
|
||||
|
||||
mCurLineLayer = lineLayer;
|
||||
|
||||
float w = line.strokeWidth;
|
||||
|
||||
if (!line.fixed) {
|
||||
w *= mStrokeScale;
|
||||
w *= mProjectionScaleFactor;
|
||||
}
|
||||
else {
|
||||
w *= 1.2; // TODO make this dependent on dpi
|
||||
}
|
||||
boolean round = line.round;
|
||||
|
||||
for (int i = 0, pos = 0, n = mWays.length; i < n; 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
|
||||
if (length >= 4) {
|
||||
lineLayer.addLine(mWayNodes, pos, length, w, line.round);
|
||||
lineLayer.addLine(mWayNodes, pos, length);
|
||||
countLines++;
|
||||
countNodes += length;
|
||||
}
|
||||
pos += length;
|
||||
}
|
||||
|
||||
if (line.outline < 0)
|
||||
return;
|
||||
|
||||
Line outline = MapGenerator.renderTheme.getOutline(line.outline);
|
||||
|
||||
if (outline == null)
|
||||
return;
|
||||
|
||||
numLayer = mDrawingLayer + outline.level;
|
||||
|
||||
l = mLineLayers;
|
||||
|
||||
if (l == null || l.layer > numLayer) {
|
||||
// insert new layer at start
|
||||
outlineLayer = new LineLayer(numLayer, outline, true);
|
||||
outlineLayer.next = l;
|
||||
mLineLayers = outlineLayer;
|
||||
} else {
|
||||
while (l != null) {
|
||||
if (l.layer == numLayer) {
|
||||
outlineLayer = l;
|
||||
break;
|
||||
}
|
||||
// insert new layer between current and next layer
|
||||
if (l.next == null || l.next.layer > numLayer) {
|
||||
outlineLayer = new LineLayer(numLayer, outline, true);
|
||||
outlineLayer.next = l.next;
|
||||
l.next = outlineLayer;
|
||||
}
|
||||
l = l.next;
|
||||
}
|
||||
}
|
||||
|
||||
if (outlineLayer != null)
|
||||
outlineLayer.addOutline(lineLayer);
|
||||
// if (line.outline < 0)
|
||||
// return;
|
||||
//
|
||||
// Line outline = MapGenerator.renderTheme.getOutline(line.outline);
|
||||
//
|
||||
// if (outline == null)
|
||||
// return;
|
||||
//
|
||||
// numLayer = mDrawingLayer + outline.getLevel();
|
||||
//
|
||||
// l = mLineLayers;
|
||||
//
|
||||
// if (l == null || l.layer > numLayer) {
|
||||
// // insert new layer at start
|
||||
// outlineLayer = new LineLayer(numLayer, outline, w, true);
|
||||
// // outlineLayer = LineLayers.get(numLayer, outline, w, true);
|
||||
// outlineLayer.next = l;
|
||||
// mLineLayers = outlineLayer;
|
||||
// } else {
|
||||
// while (l != null) {
|
||||
// if (l.layer == numLayer) {
|
||||
// outlineLayer = l;
|
||||
// break;
|
||||
// }
|
||||
// // insert new layer between current and next layer
|
||||
// if (l.next == null || l.next.layer > numLayer) {
|
||||
// outlineLayer = new LineLayer(numLayer, outline, w, true);
|
||||
// // outlineLayer = LineLayers.get(numLayer, outline, w, true);
|
||||
// outlineLayer.next = l.next;
|
||||
// l.next = outlineLayer;
|
||||
// }
|
||||
// l = l.next;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// if (outlineLayer != null)
|
||||
// outlineLayer.addOutline(lineLayer);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderArea(Area area) {
|
||||
public void renderArea(Area area, int level) {
|
||||
if (!mDebugDrawPolygons)
|
||||
return;
|
||||
|
||||
if (!projectToTile())
|
||||
if (!mProjected && !projectToTile())
|
||||
return;
|
||||
|
||||
int numLayer = mDrawingLayer + area.level;
|
||||
int numLayer = mDrawingLayer + level;
|
||||
|
||||
PolygonLayer layer = null;
|
||||
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++) {
|
||||
int length = mWays[i];
|
||||
if (length < 0)
|
||||
break;
|
||||
|
||||
// need at least three points
|
||||
if (length >= 6)
|
||||
layer.addPolygon(mWayNodes, pos, length);
|
||||
@ -470,6 +450,7 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
|
||||
pos += length;
|
||||
}
|
||||
|
||||
// if (area.line != null)
|
||||
}
|
||||
|
||||
@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
|
||||
public void cleanup() {
|
||||
// TODO Auto-generated method stub
|
||||
@ -495,23 +470,27 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
|
||||
|
||||
@Override
|
||||
public boolean executeJob(MapGeneratorJob mapGeneratorJob) {
|
||||
GLMapTile tile;
|
||||
|
||||
if (mMapDatabase == null)
|
||||
return false;
|
||||
|
||||
useSphericalMercator = WebMercator.NAME.equals(mMapDatabase.getMapProjection());
|
||||
|
||||
mCurrentTile = (GLMapTile) mapGeneratorJob.tile;
|
||||
tile = mCurrentTile = (GLMapTile) mapGeneratorJob.tile;
|
||||
mDebugDrawPolygons = !mapGeneratorJob.debugSettings.mDisablePolygons;
|
||||
mDebugDrawUnmatched = mapGeneratorJob.debugSettings.mDrawUnmatchted;
|
||||
if (mCurrentTile.isLoading || mCurrentTile.isReady)
|
||||
|
||||
if (tile.isLoading || tile.isReady || tile.isCanceled)
|
||||
return false;
|
||||
|
||||
mCurrentTile.isLoading = true;
|
||||
tile.isLoading = true;
|
||||
|
||||
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;
|
||||
mPolyLayers = null;
|
||||
@ -520,43 +499,54 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
|
||||
// firstMatch = true;
|
||||
countLines = 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);
|
||||
PolygonLayers.clear(mPolyLayers);
|
||||
mLineLayers = null;
|
||||
mPolyLayers = null;
|
||||
mCurrentTile.isLoading = false;
|
||||
tile.isLoading = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
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 + " "
|
||||
+ mCurrentTile.toString(), false);
|
||||
mPoiX = 10;
|
||||
+ tile.toString(), false);
|
||||
mPoiX = Tile.TILE_SIZE >> 1;
|
||||
mPoiY = 10;
|
||||
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 };
|
||||
// LineLayer ll = mLineLayers.getLayer(Integer.MAX_VALUE, Color.BLACK, false,
|
||||
// true, -1);
|
||||
// ll.addLine(coords, 0, coords.length, 1.5f, false);
|
||||
|
||||
mWays = debugBoxIndex;
|
||||
mWayNodes = debugBoxCoords;
|
||||
mDrawingLayer = 10 * mLevels;
|
||||
MapGenerator.renderTheme.matchWay(this, debugTagBox, (byte) 0, false, true);
|
||||
}
|
||||
mCurrentTile.lineLayers = mLineLayers;
|
||||
mCurrentTile.polygonLayers = mPolyLayers;
|
||||
mCurrentTile.labels = mLabels;
|
||||
tile.lineLayers = mLineLayers;
|
||||
tile.polygonLayers = mPolyLayers;
|
||||
tile.labels = mLabels;
|
||||
mCurPolyLayer = null;
|
||||
mCurLineLayer = null;
|
||||
|
||||
mCurrentTile.newData = true;
|
||||
tile.newData = true;
|
||||
tile.isLoading = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private Tag[] debugTagWay = { new Tag("debug", "way") };
|
||||
private Tag[] debugTagArea = { new Tag("debug", "area") };
|
||||
private final Tag[] debugTagBox = { new Tag("debug", "box") };
|
||||
private final Tag[] debugTagWay = { new Tag("debug", "way") };
|
||||
private final Tag[] debugTagArea = { new Tag("debug", "area") };
|
||||
|
||||
private float mProjectionScaleFactor;
|
||||
|
||||
@ -586,9 +576,12 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
|
||||
mStrokeScale = 1;
|
||||
}
|
||||
|
||||
private String mMapProjection;
|
||||
|
||||
@Override
|
||||
public void setMapDatabase(IMapDatabase mapDatabase) {
|
||||
mMapDatabase = mapDatabase;
|
||||
mMapProjection = mMapDatabase.getMapProjection();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -609,4 +602,76 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
|
||||
|
||||
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
@ -15,11 +15,14 @@
|
||||
package org.mapsforge.android.glrenderer;
|
||||
|
||||
import org.mapsforge.android.rendertheme.renderinstruction.Area;
|
||||
import org.mapsforge.core.Tile;
|
||||
|
||||
class PolygonLayer {
|
||||
private static final float S = MapRenderer.COORD_MULTIPLIER;
|
||||
|
||||
PolygonLayer next;
|
||||
Area area;
|
||||
private static final float SCALE_FACTOR = 16.0f;
|
||||
// private static final float MapRenderer.COORD_MULTIPLIER = 8.0f;
|
||||
private boolean first = true;
|
||||
private float originX;
|
||||
private float originY;
|
||||
@ -53,8 +56,8 @@ class PolygonLayer {
|
||||
|
||||
if (first) {
|
||||
first = false;
|
||||
originX = points[pos];
|
||||
originY = points[pos + 1];
|
||||
originX = Tile.TILE_SIZE >> 1; // points[pos];
|
||||
originY = Tile.TILE_SIZE >> 1; // points[pos + 1];
|
||||
}
|
||||
|
||||
short[] curVertices = curItem.vertices;
|
||||
@ -65,24 +68,25 @@ class PolygonLayer {
|
||||
outPos = 0;
|
||||
}
|
||||
|
||||
curVertices[outPos++] = (short) (originX * SCALE_FACTOR);
|
||||
curVertices[outPos++] = (short) (originY * SCALE_FACTOR);
|
||||
curVertices[outPos++] = (short) (originX * S);
|
||||
curVertices[outPos++] = (short) (originY * S);
|
||||
|
||||
int MAX = ShortItem.SIZE;
|
||||
int remaining = length;
|
||||
int inPos = pos;
|
||||
while (remaining > 0) {
|
||||
|
||||
if (outPos == ShortItem.SIZE) {
|
||||
if (outPos == MAX) {
|
||||
curVertices = getNextItem();
|
||||
outPos = 0;
|
||||
}
|
||||
|
||||
int len = remaining;
|
||||
if (len > (ShortItem.SIZE) - outPos)
|
||||
len = (ShortItem.SIZE) - outPos;
|
||||
if (len > MAX - outPos)
|
||||
len = MAX - outPos;
|
||||
|
||||
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);
|
||||
|
||||
@ -92,13 +96,13 @@ class PolygonLayer {
|
||||
remaining -= len;
|
||||
}
|
||||
|
||||
if (outPos == PoolItem.SIZE) {
|
||||
if (outPos == MAX) {
|
||||
curVertices = getNextItem();
|
||||
outPos = 0;
|
||||
}
|
||||
|
||||
curVertices[outPos++] = (short) (points[pos + 0] * SCALE_FACTOR);
|
||||
curVertices[outPos++] = (short) (points[pos + 1] * SCALE_FACTOR);
|
||||
curVertices[outPos++] = (short) (points[pos + 0] * S);
|
||||
curVertices[outPos++] = (short) (points[pos + 1] * S);
|
||||
|
||||
curItem.used = outPos;
|
||||
}
|
||||
|
||||
@ -14,172 +14,269 @@
|
||||
*/
|
||||
package org.mapsforge.android.glrenderer;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import static android.opengl.GLES20.GL_BLEND;
|
||||
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 org.mapsforge.core.Tile;
|
||||
import org.mapsforge.android.utils.GlUtils;
|
||||
|
||||
import android.opengl.GLES20;
|
||||
|
||||
class PolygonLayers {
|
||||
private static final int NUM_VERTEX_FLOATS = 2;
|
||||
// static final float[] mFillCoords = { -2, Tile.TILE_SIZE + 1,
|
||||
// Tile.TILE_SIZE + 1, Tile.TILE_SIZE + 1, -2,
|
||||
// -2, Tile.TILE_SIZE + 1, -2 };
|
||||
private static final int NUM_VERTEX_SHORTS = 2;
|
||||
private static final int POLYGON_VERTICES_DATA_POS_OFFSET = 0;
|
||||
private static int STENCIL_BITS = 8;
|
||||
|
||||
// private static short[] mByteFillCoords = null;
|
||||
private static PolygonLayer[] mFillPolys;
|
||||
|
||||
// static FloatBuffer compileLayerData(PolygonLayer layers, FloatBuffer buf) {
|
||||
// FloatBuffer fbuf = buf;
|
||||
// int size = 4;
|
||||
//
|
||||
// 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];
|
||||
private static int polygonProgram;
|
||||
private static int hPolygonVertexPosition;
|
||||
private static int hPolygonMatrix;
|
||||
private static int hPolygonColor;
|
||||
|
||||
// static ShortBuffer compileLayerData(PolygonLayer layers, ShortBuffer buf) {
|
||||
// ShortBuffer sbuf = buf;
|
||||
// int size = 4;
|
||||
static boolean init() {
|
||||
|
||||
// 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)
|
||||
// size += l.verticesCnt;
|
||||
// int c = drawCount % 16;
|
||||
// // 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) {
|
||||
// ByteBuffer bbuf = ByteBuffer.allocateDirect(size * 2).order(
|
||||
// ByteOrder.nativeOrder());
|
||||
// sbuf = bbuf.asShortBuffer();
|
||||
// } else {
|
||||
// sbuf.clear();
|
||||
// }
|
||||
// // set stencilbuffer for (tile region)
|
||||
// glStencilOp(GLES20.GL_REPLACE, GLES20.GL_KEEP, GLES20.GL_KEEP);
|
||||
// glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
//
|
||||
// short[] data = tmpItem;
|
||||
// glStencilFunc(GL_EQUAL, flipdabit[c], 0xff);
|
||||
// // do not modify stencil buffer
|
||||
// glStencilMask(0);
|
||||
//
|
||||
// if (mByteFillCoords == null) {
|
||||
// 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);
|
||||
// }
|
||||
// glColorMask(true, true, true, true);
|
||||
// }
|
||||
|
||||
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) {
|
||||
ShortBuffer sbuf = buf;
|
||||
int size = 4;
|
||||
static void drawDepthClip(short drawCount) {
|
||||
|
||||
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)
|
||||
size += l.verticesCnt;
|
||||
|
||||
size *= NUM_VERTEX_FLOATS;
|
||||
size *= NUM_VERTEX_SHORTS;
|
||||
|
||||
if (buf == null || buf.capacity() < size) {
|
||||
ByteBuffer bbuf = ByteBuffer.allocateDirect(size * 2).order(
|
||||
ByteOrder.nativeOrder());
|
||||
sbuf = bbuf.asShortBuffer();
|
||||
} else {
|
||||
sbuf.clear();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
if (mFillCoords == null) {
|
||||
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);
|
||||
static void compileLayerData(PolygonLayer layers, ShortBuffer sbuf) {
|
||||
int pos = 4;
|
||||
|
||||
ShortItem last = null, items = null;
|
||||
@ -203,10 +300,6 @@ class PolygonLayers {
|
||||
}
|
||||
|
||||
ShortPool.add(items);
|
||||
|
||||
sbuf.flip();
|
||||
|
||||
return sbuf;
|
||||
}
|
||||
|
||||
static void clear(PolygonLayer layers) {
|
||||
|
||||
@ -16,166 +16,141 @@
|
||||
package org.mapsforge.android.glrenderer;
|
||||
|
||||
class Shaders {
|
||||
final static String gLineVertexShader = ""
|
||||
|
||||
final static String lineVertexShader = ""
|
||||
+ "precision mediump float; \n"
|
||||
+ "uniform mat4 u_center;"
|
||||
+ "uniform mat4 mvp;"
|
||||
+ "attribute vec4 a_position;"
|
||||
+ "attribute vec2 a_st;"
|
||||
+ "varying vec2 v_st;"
|
||||
+ "const vec4 scale = vec4(1.0/16.0, 1.0/16.0, 0.0, 1.0);"
|
||||
+ "uniform float u_width;"
|
||||
+ "uniform float u_offset;"
|
||||
+ "const float dscale = 8.0/1000.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;"
|
||||
+ " vec2 dir = dscale * u_width * a_position.zw;"
|
||||
+ " gl_Position = mvp * vec4(a_position.xy + dir, 0.0,1.0);"
|
||||
+ " v_st = u_width * a_st;"
|
||||
+ "}";
|
||||
|
||||
final static String gLineFragmentShader = ""
|
||||
// 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;"
|
||||
+ "uniform lowp vec2 u_mode;"
|
||||
+ "precision mediump float;\n"
|
||||
+ "uniform float u_wscale;"
|
||||
+ "uniform float u_width;"
|
||||
+ "uniform vec4 u_color;"
|
||||
+ "const lowp float zero = 0.0;"
|
||||
+ "const float fuzzf = 1.8;"
|
||||
+ "varying vec2 v_st;"
|
||||
+ "const float zero = 0.0;"
|
||||
+ "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);"
|
||||
+ " }"
|
||||
+ " vec4 color = u_color;"
|
||||
+ " float width = u_width;"
|
||||
+ " float len;"
|
||||
+ " if (v_st.t == zero)"
|
||||
+ " len = abs(v_st.s);"
|
||||
+ " else "
|
||||
+ " len = length(v_st);"
|
||||
// + " 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 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 = ""
|
||||
final static String polygonVertexShader = ""
|
||||
+ "precision mediump float;"
|
||||
+ "uniform vec4 u_color;"
|
||||
+ "uniform vec2 u_mode;"
|
||||
+ "uniform float u_width;"
|
||||
+ "varying vec2 v_st;"
|
||||
+ "void main() {"
|
||||
+ " gl_FragColor = u_color;"
|
||||
+ " float width = u_width * u_mode[1];"
|
||||
+ " float len;"
|
||||
+ " if (v_st.t == 0.0) "
|
||||
+ " len = abs(v_st.s);"
|
||||
+ " else "
|
||||
+ " len = length(v_st);"
|
||||
+ " gl_FragColor.a = smoothstep(width, width - u_mode[1], width * len);"
|
||||
|
||||
+ "}";
|
||||
|
||||
final static String gPolygonVertexShader = ""
|
||||
+ "precision mediump float; \n"
|
||||
+ "uniform mat4 u_center;\n"
|
||||
+ "uniform mat4 mvp;"
|
||||
+ "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() {"
|
||||
+ " gl_Position = u_center * (scale * a_position);"
|
||||
+ " gl_Position = mvp * a_position;"
|
||||
+ "}";
|
||||
|
||||
final static String gPolygonFragmentShader = ""
|
||||
final static String polygonFragmentShader = ""
|
||||
+ "precision mediump float;"
|
||||
+ "uniform vec4 u_color;"
|
||||
+ "void main() {"
|
||||
+ " 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;"
|
||||
// + "}";
|
||||
}
|
||||
|
||||
@ -24,5 +24,6 @@ public class ShortItem {
|
||||
used = 0;
|
||||
}
|
||||
|
||||
static int SIZE = 128;
|
||||
// must be multiple of 6 and 4 (expected in LineLayer/PolygonLayer)
|
||||
static final int SIZE = 240;
|
||||
}
|
||||
|
||||
@ -14,59 +14,80 @@
|
||||
*/
|
||||
package org.mapsforge.android.glrenderer;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.util.Log;
|
||||
|
||||
public class ShortPool {
|
||||
private static final int POOL_LIMIT = 8192;
|
||||
|
||||
@SuppressLint("UseValueOf")
|
||||
private static final Boolean lock = new Boolean(true);
|
||||
private static final int POOL_LIMIT = 6000;
|
||||
|
||||
static private ShortItem pool = null;
|
||||
static private int count = 0;
|
||||
static private int countAll = 0;
|
||||
|
||||
static ShortItem get() {
|
||||
synchronized (lock) {
|
||||
|
||||
if (count == 0)
|
||||
return new ShortItem();
|
||||
|
||||
count--;
|
||||
|
||||
ShortItem it = pool;
|
||||
pool = pool.next;
|
||||
it.used = 0;
|
||||
it.next = null;
|
||||
return it;
|
||||
}
|
||||
static synchronized void finish() {
|
||||
count = 0;
|
||||
countAll = 0;
|
||||
pool = null;
|
||||
}
|
||||
|
||||
static void add(ShortItem items) {
|
||||
static synchronized ShortItem get() {
|
||||
|
||||
if (pool == null) {
|
||||
countAll++;
|
||||
return new ShortItem();
|
||||
}
|
||||
|
||||
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;
|
||||
pool = pool.next;
|
||||
it.used = 0;
|
||||
it.next = null;
|
||||
return it;
|
||||
}
|
||||
|
||||
static synchronized void add(ShortItem items) {
|
||||
if (items == null)
|
||||
return;
|
||||
|
||||
synchronized (lock) {
|
||||
// limit pool items
|
||||
if (countAll < POOL_LIMIT) {
|
||||
|
||||
ShortItem last = items;
|
||||
|
||||
// limit pool items
|
||||
while (count < POOL_LIMIT) {
|
||||
if (last.next == null) {
|
||||
break;
|
||||
}
|
||||
last = last.next;
|
||||
while (true) {
|
||||
count++;
|
||||
}
|
||||
|
||||
// clear references
|
||||
ShortItem tmp2, tmp = last.next;
|
||||
while (tmp != null) {
|
||||
tmp2 = tmp;
|
||||
tmp = tmp.next;
|
||||
tmp2.next = null;
|
||||
if (last.next == null)
|
||||
break;
|
||||
|
||||
last = last.next;
|
||||
}
|
||||
|
||||
last.next = pool;
|
||||
pool = items;
|
||||
|
||||
} else {
|
||||
// int cleared = 0;
|
||||
ShortItem prev, tmp = items;
|
||||
while (tmp != null) {
|
||||
prev = tmp;
|
||||
tmp = tmp.next;
|
||||
|
||||
countAll--;
|
||||
|
||||
prev.next = null;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
package org.mapsforge.android.glrenderer;
|
||||
|
||||
import org.mapsforge.android.rendertheme.renderinstruction.Caption;
|
||||
import org.mapsforge.android.rendertheme.renderinstruction.PathText;
|
||||
|
||||
public class TextItem {
|
||||
TextItem next;
|
||||
@ -22,14 +23,27 @@ public class TextItem {
|
||||
final float x, y;
|
||||
final String text;
|
||||
final Caption caption;
|
||||
final PathText path;
|
||||
final float width;
|
||||
|
||||
short x1, y1, x2, y2;
|
||||
|
||||
public TextItem(float x, float y, String text, Caption caption) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.text = text;
|
||||
this.caption = caption;
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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
|
||||
* 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.opengl.GLES20;
|
||||
import android.opengl.GLUtils;
|
||||
import android.util.FloatMath;
|
||||
import android.util.Log;
|
||||
|
||||
public class TextRenderer {
|
||||
private final static int TEXTURE_WIDTH = 512;
|
||||
private final static int TEXTURE_HEIGHT = 256;
|
||||
private final static float SCALE_FACTOR = 8.0f;
|
||||
|
||||
final static int MAX_LABELS = 30;
|
||||
|
||||
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 INDICES_PER_SPRITE = 6;
|
||||
final static int VERTICES_PER_SPRITE = 4;
|
||||
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;
|
||||
static int hTextUVPMatrix;
|
||||
static int hTextVertex;
|
||||
static int hTextScale;
|
||||
static int hTextTextureCoord;
|
||||
static int hTextUColor;
|
||||
private static int hTextUVPMatrix;
|
||||
private static int hTextVertex;
|
||||
private static int hTextScale;
|
||||
private static int hTextTextureCoord;
|
||||
// private static int hTextUColor;
|
||||
|
||||
static Paint mPaint = new Paint(Color.BLACK);
|
||||
|
||||
boolean debug = false;
|
||||
short[] debugVertices = {
|
||||
private static boolean debug = false;
|
||||
private static short[] debugVertices = {
|
||||
|
||||
0, 0,
|
||||
0, TEXTURE_HEIGHT,
|
||||
0, TEXTURE_HEIGHT * 4,
|
||||
|
||||
0, TEXTURE_HEIGHT - 1,
|
||||
0, 0,
|
||||
|
||||
TEXTURE_WIDTH - 1, 0,
|
||||
TEXTURE_WIDTH, TEXTURE_HEIGHT,
|
||||
TEXTURE_WIDTH * 4, TEXTURE_HEIGHT * 4,
|
||||
|
||||
TEXTURE_WIDTH - 1, TEXTURE_HEIGHT - 1,
|
||||
TEXTURE_WIDTH, 0,
|
||||
TEXTURE_WIDTH * 4, 0,
|
||||
|
||||
};
|
||||
|
||||
TextRenderer(int numTextures) {
|
||||
static boolean init(int numTextures) {
|
||||
mBitmap = Bitmap
|
||||
.createBitmap(TEXTURE_WIDTH, TEXTURE_HEIGHT, Bitmap.Config.ARGB_8888);
|
||||
mCanvas = new Canvas(mBitmap);
|
||||
@ -85,15 +86,14 @@ public class TextRenderer {
|
||||
mBitmapFormat = GLUtils.getInternalFormat(mBitmap);
|
||||
mBitmapType = GLUtils.getType(mBitmap);
|
||||
|
||||
mTextProgram = GlUtils.createProgram(textVertexShader, textFragmentShader);
|
||||
mTextProgram = GlUtils.createProgram(Shaders.textVertexShader,
|
||||
Shaders.textFragmentShader);
|
||||
|
||||
hTextUVPMatrix = GLES20.glGetUniformLocation(mTextProgram, "mvp");
|
||||
hTextUColor = GLES20.glGetUniformLocation(mTextProgram, "col");
|
||||
hTextVertex = GLES20.glGetAttribLocation(mTextProgram, "vertex");
|
||||
hTextScale = GLES20.glGetUniformLocation(mTextProgram, "scale");
|
||||
hTextTextureCoord = GLES20.glGetAttribLocation(mTextProgram, "tex_coord");
|
||||
|
||||
// mVertexBuffer = new float[];
|
||||
int bufferSize = numTextures
|
||||
* MAX_LABELS * VERTICES_PER_SPRITE
|
||||
* SHORTS_PER_VERTICE * (Short.SIZE / 8);
|
||||
@ -121,12 +121,12 @@ public class TextRenderer {
|
||||
GLES20.GL_CLAMP_TO_EDGE); // Set V Wrapping
|
||||
|
||||
// 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,
|
||||
mBitmapType, 0);
|
||||
|
||||
textures[i] = new TextTexture(textureIds[i]);
|
||||
}
|
||||
|
||||
GlUtils.checkGlError("init textures");
|
||||
|
||||
mTextures = textures;
|
||||
@ -136,12 +136,18 @@ public class TextRenderer {
|
||||
int len = indices.length;
|
||||
short j = 0;
|
||||
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 + 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 + 1] = (short) (j + 0);
|
||||
indices[i + 2] = (short) (j + 1);
|
||||
indices[i + 3] = (short) (j + 3);
|
||||
indices[i + 4] = (short) (j + 2);
|
||||
indices[i + 5] = (short) (j + 2);
|
||||
}
|
||||
|
||||
ShortBuffer tmpIndices = mByteBuffer.asShortBuffer();
|
||||
@ -151,21 +157,25 @@ public class TextRenderer {
|
||||
|
||||
int[] mVboIds = new int[2];
|
||||
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];
|
||||
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;
|
||||
|
||||
if (tile.labels.size() == 0)
|
||||
if (tile.labels == null)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < mTextures.length; i++) {
|
||||
@ -194,9 +204,7 @@ public class TextRenderer {
|
||||
float x = mFontPadX;
|
||||
float width, height;
|
||||
|
||||
int max = tile.labels.size();
|
||||
if (max > MAX_LABELS)
|
||||
max = MAX_LABELS;
|
||||
int max = MAX_LABELS;
|
||||
|
||||
if (debug) {
|
||||
mCanvas.drawLine(debugVertices[0], debugVertices[1], debugVertices[4],
|
||||
@ -212,10 +220,18 @@ public class TextRenderer {
|
||||
|
||||
int advanceY = 0;
|
||||
|
||||
for (int i = 0; i < max; i++) {
|
||||
TextItem t = tile.labels.get(i);
|
||||
TextItem t = tile.labels;
|
||||
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;
|
||||
} else {
|
||||
height = (int) (t.path.fontHeight) + 2 * mFontPadY;
|
||||
}
|
||||
|
||||
height = (int) (t.caption.fontHeight) + 2 * mFontPadY;
|
||||
width = t.width + 2 * mFontPadX;
|
||||
|
||||
if (height > advanceY)
|
||||
@ -227,45 +243,71 @@ public class TextRenderer {
|
||||
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) {
|
||||
Log.d(TAG, "reached max labels");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (t.caption.stroke != null)
|
||||
mCanvas.drawText(t.text, x + t.width / 2, yy, t.caption.stroke);
|
||||
if (t.caption != 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.paint);
|
||||
|
||||
// Log.d(TAG, "draw: " + t.text + " at:" + (xx + t.width / 2) + " " + yy + " w:"
|
||||
// + t.width + " " + cellHeight);
|
||||
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);
|
||||
|
||||
mCanvas.drawText(t.text, x + t.width / 2, yy, t.path.paint);
|
||||
}
|
||||
if (width > TEXTURE_WIDTH)
|
||||
width = TEXTURE_WIDTH;
|
||||
|
||||
float halfWidth = width / 2.0f;
|
||||
float halfHeight = height / 2.0f;
|
||||
float hw = width / 2.0f;
|
||||
float hh = height / 2.0f;
|
||||
|
||||
// short x1 = (short) (2.0f * (t.x - halfWidth));
|
||||
// short y1 = (short) (2.0f * (t.y - halfHeight));
|
||||
// short x2 = (short) (2.0f * (t.x + halfWidth));
|
||||
// short y2 = (short) (2.0f * (t.y + halfHeight));
|
||||
if (t.caption != null) {
|
||||
x1 = x3 = (short) (SCALE_FACTOR * (-hw));
|
||||
y1 = y3 = (short) (SCALE_FACTOR * (-hh));
|
||||
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));
|
||||
short y1 = (short) (2.0f * (-halfHeight));
|
||||
short x2 = (short) (2.0f * (halfWidth));
|
||||
short y2 = (short) (2.0f * (halfHeight));
|
||||
float ux = -vy;
|
||||
float uy = vx;
|
||||
|
||||
short u1 = (short) (2.0f * x);
|
||||
short v1 = (short) (2.0f * y);
|
||||
short u2 = (short) (2.0f * (x + width));
|
||||
short v2 = (short) (2.0f * (y + height));
|
||||
x1 = (short) (SCALE_FACTOR * (vx * hw + ux * hh));
|
||||
y1 = (short) (SCALE_FACTOR * (vy * hw + uy * hh));
|
||||
|
||||
short tx = (short) (2.0f * t.x);
|
||||
short ty = (short) (2.0f * t.y);
|
||||
x2 = (short) (SCALE_FACTOR * (-vx * hw + ux * hh));
|
||||
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++] = ty;
|
||||
buf[pos++] = x1;
|
||||
@ -273,23 +315,26 @@ public class TextRenderer {
|
||||
buf[pos++] = u1;
|
||||
buf[pos++] = v2;
|
||||
|
||||
// top-right
|
||||
buf[pos++] = tx;
|
||||
buf[pos++] = ty;
|
||||
buf[pos++] = x2;
|
||||
buf[pos++] = y1;
|
||||
buf[pos++] = y3;
|
||||
buf[pos++] = u2;
|
||||
buf[pos++] = v2;
|
||||
|
||||
// bot-right
|
||||
buf[pos++] = tx;
|
||||
buf[pos++] = ty;
|
||||
buf[pos++] = x2;
|
||||
buf[pos++] = y2;
|
||||
buf[pos++] = x4;
|
||||
buf[pos++] = y4;
|
||||
buf[pos++] = u2;
|
||||
buf[pos++] = v1;
|
||||
|
||||
// bot-left
|
||||
buf[pos++] = tx;
|
||||
buf[pos++] = ty;
|
||||
buf[pos++] = x1;
|
||||
buf[pos++] = x3;
|
||||
buf[pos++] = y2;
|
||||
buf[pos++] = u1;
|
||||
buf[pos++] = v1;
|
||||
@ -305,19 +350,16 @@ public class TextRenderer {
|
||||
tex.length = pos;
|
||||
tile.texture = tex;
|
||||
tex.tile = tile;
|
||||
// GlUtils.checkGlError("0");
|
||||
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, tex.id);
|
||||
// GlUtils.checkGlError("1");
|
||||
GLUtils.texSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, mBitmap, mBitmapFormat,
|
||||
mBitmapType);
|
||||
// GlUtils.checkGlError("2");
|
||||
GLUtils.texSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, mBitmap,
|
||||
mBitmapFormat, mBitmapType);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static String TAG = "TextRenderer";
|
||||
|
||||
void compileTextures() {
|
||||
static void compileTextures() {
|
||||
int offset = 0;
|
||||
TextTexture tex;
|
||||
|
||||
@ -339,16 +381,18 @@ public class TextRenderer {
|
||||
// Log.d(TAG, "compileTextures" + mFloatBuffer.remaining() + " " + offset);
|
||||
|
||||
// TODO use sub-bufferdata function
|
||||
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, offset * (Short.SIZE / 8),
|
||||
mShortBuffer, GLES20.GL_DYNAMIC_DRAW);
|
||||
GLES20.glBufferSubData(GLES20.GL_ARRAY_BUFFER, 0, offset * (Short.SIZE / 8),
|
||||
mShortBuffer);
|
||||
}
|
||||
|
||||
void beginDraw(float scale) {
|
||||
static void beginDraw(float scale) {
|
||||
GLES20.glUseProgram(mTextProgram);
|
||||
|
||||
GLES20.glEnableVertexAttribArray(hTextTextureCoord);
|
||||
GLES20.glEnableVertexAttribArray(hTextVertex);
|
||||
|
||||
GLES20.glUniform1f(hTextScale, scale);
|
||||
|
||||
if (debug) {
|
||||
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
|
||||
mShortBuffer.clear();
|
||||
@ -365,13 +409,13 @@ public class TextRenderer {
|
||||
}
|
||||
}
|
||||
|
||||
void endDraw() {
|
||||
static void endDraw() {
|
||||
|
||||
GLES20.glDisableVertexAttribArray(hTextTextureCoord);
|
||||
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);
|
||||
|
||||
@ -384,43 +428,12 @@ public class TextRenderer {
|
||||
GLES20.glVertexAttribPointer(hTextVertex, 4,
|
||||
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.GL_SHORT, false, 12, tile.texture.offset * (Short.SIZE / 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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);"
|
||||
+ "}";
|
||||
|
||||
}
|
||||
|
||||
285
src/org/mapsforge/android/glrenderer/WayDecorator.java
Normal file
285
src/org/mapsforge/android/glrenderer/WayDecorator.java
Normal 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();
|
||||
}
|
||||
}
|
||||
@ -19,14 +19,12 @@ import org.mapsforge.core.Tile;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.CountDownTimer;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.GestureDetector.SimpleOnGestureListener;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.ScaleGestureDetector;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.widget.Scroller;
|
||||
|
||||
/**
|
||||
@ -220,27 +218,15 @@ public class TouchHandler {
|
||||
}
|
||||
|
||||
// if (ret) {
|
||||
// Log.d("", "" + );
|
||||
//
|
||||
// // try {
|
||||
// //
|
||||
// // Thread.sleep(10);
|
||||
// // } catch (InterruptedException e) {
|
||||
// // // TODO Auto-generated catch block
|
||||
// // // e.printStackTrace();
|
||||
// // }
|
||||
//
|
||||
// // throttle input
|
||||
// long diff = SystemClock.uptimeMillis() - lastRun;
|
||||
// if (diff < 16 && diff > 5) {
|
||||
// // Log.d("", "" + diff);
|
||||
// SystemClock.sleep(16 - diff);
|
||||
// }
|
||||
if (ret) {
|
||||
// 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
|
||||
// lastRun = SystemClock.uptimeMillis();
|
||||
// }
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -250,7 +236,8 @@ public class TouchHandler {
|
||||
private CountDownTimer mTimer = null;
|
||||
|
||||
public MapGestureDetector(MapView mapView) {
|
||||
mScroller = new Scroller(mapView.getContext(), new DecelerateInterpolator());
|
||||
mScroller = new Scroller(mapView.getContext(),
|
||||
new android.view.animation.LinearInterpolator());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -284,8 +271,8 @@ public class TouchHandler {
|
||||
@Override
|
||||
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
|
||||
float velocityY) {
|
||||
int w = Tile.TILE_SIZE * 20;
|
||||
int h = Tile.TILE_SIZE * 20;
|
||||
int w = Tile.TILE_SIZE * 10;
|
||||
int h = Tile.TILE_SIZE * 10;
|
||||
mPrevX = 0;
|
||||
mPrevY = 0;
|
||||
|
||||
@ -297,7 +284,7 @@ public class TouchHandler {
|
||||
mScroller.fling(0, 0, Math.round(velocityX) / 2, Math.round(velocityY) / 2,
|
||||
-w, w, -h, h);
|
||||
// animate for two seconds
|
||||
mTimer = new CountDownTimer(2000, 20) {
|
||||
mTimer = new CountDownTimer(2000, 40) {
|
||||
@Override
|
||||
public void onTick(long tick) {
|
||||
if (!scroll())
|
||||
|
||||
@ -46,14 +46,14 @@ public class JobQueue {
|
||||
* @param mapGeneratorJob
|
||||
* the job to be added to this queue.
|
||||
*/
|
||||
public synchronized void addJob(MapGeneratorJob mapGeneratorJob) {
|
||||
if (!mPriorityQueue.contains(mapGeneratorJob))
|
||||
// priorityQueue.remove(mapGeneratorJob);
|
||||
{
|
||||
mapGeneratorJob.tile.isLoading = true;
|
||||
mPriorityQueue.offer(mapGeneratorJob);
|
||||
}
|
||||
}
|
||||
// public synchronized void addJob(MapGeneratorJob mapGeneratorJob) {
|
||||
// if (!mPriorityQueue.contains(mapGeneratorJob))
|
||||
// // priorityQueue.remove(mapGeneratorJob);
|
||||
// {
|
||||
// //mapGeneratorJob.tile.isLoading = true;
|
||||
// mPriorityQueue.offer(mapGeneratorJob);
|
||||
// }
|
||||
// }
|
||||
|
||||
/**
|
||||
* @param jobs
|
||||
|
||||
@ -43,7 +43,7 @@ public class MapTile extends Tile {
|
||||
/**
|
||||
* distance from center, used in TileScheduler set by updateVisibleList.
|
||||
*/
|
||||
public long distance;
|
||||
public float distance;
|
||||
|
||||
/**
|
||||
* @param tileX
|
||||
|
||||
@ -86,7 +86,7 @@ public class MapWorker extends PausableThread {
|
||||
|
||||
@Override
|
||||
protected int getThreadPriority() {
|
||||
return (Thread.NORM_PRIORITY + Thread.MIN_PRIORITY) / 2;
|
||||
return (Thread.NORM_PRIORITY + Thread.MIN_PRIORITY) / 3;
|
||||
// return mPrio;
|
||||
}
|
||||
|
||||
|
||||
@ -17,6 +17,7 @@ package org.mapsforge.android.rendertheme;
|
||||
import org.mapsforge.android.rendertheme.renderinstruction.Area;
|
||||
import org.mapsforge.android.rendertheme.renderinstruction.Caption;
|
||||
import org.mapsforge.android.rendertheme.renderinstruction.Line;
|
||||
import org.mapsforge.android.rendertheme.renderinstruction.PathText;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Paint;
|
||||
@ -31,7 +32,7 @@ public interface IRenderCallback {
|
||||
* @param area
|
||||
* ...
|
||||
*/
|
||||
void renderArea(Area area);
|
||||
void renderArea(Area area, int level);
|
||||
|
||||
/**
|
||||
* Renders an area caption with the given text.
|
||||
@ -83,7 +84,7 @@ public interface IRenderCallback {
|
||||
* @param line
|
||||
* ...
|
||||
*/
|
||||
void renderWay(Line line);
|
||||
void renderWay(Line line, int level);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @param text
|
||||
* 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).
|
||||
* @param pathText
|
||||
* ...
|
||||
*/
|
||||
void renderWayText(String text, Paint paint, Paint stroke);
|
||||
void renderWayText(PathText pathText);
|
||||
}
|
||||
|
||||
@ -21,8 +21,9 @@ import org.mapsforge.core.Tag;
|
||||
class NegativeMatcher implements AttributeMatcher {
|
||||
private final String[] mKeyList;
|
||||
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()];
|
||||
for (int i = 0; i < mKeyList.length; i++)
|
||||
mKeyList[i] = keyList.get(i).intern();
|
||||
@ -30,6 +31,8 @@ class NegativeMatcher implements AttributeMatcher {
|
||||
mValueList = new String[valueList.size()];
|
||||
for (int i = 0; i < mValueList.length; i++)
|
||||
mValueList[i] = valueList.get(i).intern();
|
||||
|
||||
mExclusive = exclusive;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -46,9 +49,9 @@ class NegativeMatcher implements AttributeMatcher {
|
||||
for (Tag tag : tags) {
|
||||
for (String value : mValueList)
|
||||
if (value == tag.value)
|
||||
return true;
|
||||
return !mExclusive;
|
||||
}
|
||||
return false;
|
||||
return mExclusive;
|
||||
}
|
||||
|
||||
private boolean keyListDoesNotContainKeys(Tag[] tags) {
|
||||
|
||||
@ -29,14 +29,14 @@ class NegativeRule extends Rule {
|
||||
@Override
|
||||
boolean matchesNode(Tag[] tags, byte zoomLevel) {
|
||||
return mZoomMin <= zoomLevel && mZoomMax >= zoomLevel
|
||||
&& (mElement == Element.NODE || mElement == Element.ANY)
|
||||
&& (mElement != Element.WAY)
|
||||
&& mAttributeMatcher.matches(tags);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean matchesWay(Tag[] tags, byte zoomLevel, int closed) {
|
||||
return mZoomMin <= zoomLevel && mZoomMax >= zoomLevel
|
||||
&& (mElement == Element.WAY || mElement == Element.ANY)
|
||||
&& (mElement != Element.NODE)
|
||||
&& (mClosed == closed || mClosed == Closed.ANY)
|
||||
&& mAttributeMatcher.matches(tags);
|
||||
}
|
||||
|
||||
@ -37,16 +37,16 @@ class PositiveRule extends Rule {
|
||||
|
||||
@Override
|
||||
boolean matchesNode(Tag[] tags, byte zoomLevel) {
|
||||
return mZoomMin <= zoomLevel && mZoomMax >= zoomLevel
|
||||
&& (mElement == Element.NODE || mElement == Element.ANY)
|
||||
return (mElement != Element.WAY)
|
||||
&& mZoomMin <= zoomLevel && mZoomMax >= zoomLevel
|
||||
&& (mKeyMatcher == null || mKeyMatcher.matches(tags))
|
||||
&& (mValueMatcher == null || mValueMatcher.matches(tags));
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean matchesWay(Tag[] tags, byte zoomLevel, int closed) {
|
||||
return mZoomMin <= zoomLevel && mZoomMax >= zoomLevel
|
||||
&& (mElement == Element.WAY || mElement == Element.ANY)
|
||||
return (mElement != Element.NODE)
|
||||
&& mZoomMin <= zoomLevel && mZoomMax >= zoomLevel
|
||||
&& (mClosed == closed || mClosed == Closed.ANY)
|
||||
&& (mKeyMatcher == null || mKeyMatcher.matches(tags))
|
||||
&& (mValueMatcher == null || mValueMatcher.matches(tags));
|
||||
|
||||
@ -17,7 +17,6 @@ package org.mapsforge.android.rendertheme;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.mapsforge.android.rendertheme.renderinstruction.Line;
|
||||
import org.mapsforge.android.rendertheme.renderinstruction.RenderInstruction;
|
||||
import org.mapsforge.core.LRUCache;
|
||||
import org.mapsforge.core.Tag;
|
||||
@ -136,40 +135,112 @@ public class RenderTheme {
|
||||
* ...
|
||||
* @param zoomLevel
|
||||
* ...
|
||||
* @return ...
|
||||
*/
|
||||
public void matchNode(IRenderCallback renderCallback, Tag[] tags, byte zoomLevel) {
|
||||
// List<RenderInstruction> matchingList = matchingListNode;
|
||||
// MatchingCacheKey matchingCacheKey = matchingCacheKeyNode;
|
||||
public synchronized RenderInstruction[] matchNode(IRenderCallback renderCallback,
|
||||
Tag[] tags,
|
||||
byte zoomLevel) {
|
||||
|
||||
// if (!changed) {
|
||||
// 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 {
|
||||
RenderInstruction[] renderInstructions = null;
|
||||
|
||||
// cache miss
|
||||
// matchingList = new ArrayList<RenderInstruction>();
|
||||
for (int i = 0, n = mRulesList.size(); i < n; ++i) {
|
||||
mRulesList.get(i).matchNode(renderCallback, tags, zoomLevel);
|
||||
// , matchingList
|
||||
MatchingCacheKey matchingCacheKey;
|
||||
|
||||
matchingCacheKey = new MatchingCacheKey(tags, zoomLevel);
|
||||
boolean found = mMatchingCacheNodes.containsKey(matchingCacheKey);
|
||||
if (found) {
|
||||
renderInstructions = mMatchingCacheNodes.get(matchingCacheKey);
|
||||
} else {
|
||||
// cache miss
|
||||
List<RenderInstruction> matchingList = new ArrayList<RenderInstruction>(4);
|
||||
for (int i = 0, n = mRulesList.size(); i < n; ++i)
|
||||
mRulesList.get(i)
|
||||
.matchNode(renderCallback, tags, zoomLevel, matchingList);
|
||||
|
||||
int size = matchingList.size();
|
||||
if (size > 0) {
|
||||
renderInstructions = new RenderInstruction[size];
|
||||
matchingList.toArray(renderInstructions);
|
||||
}
|
||||
mMatchingCacheNodes.put(matchingCacheKey, renderInstructions);
|
||||
}
|
||||
// matchingCacheNodes.put(matchingCacheKey, matchingList);
|
||||
// }
|
||||
//
|
||||
// matchingListNode = matchingList;
|
||||
// matchingCacheKeyNode = matchingCacheKey;
|
||||
|
||||
if (renderInstructions != null) {
|
||||
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) {
|
||||
mLevels = levels;
|
||||
}
|
||||
|
||||
@ -16,6 +16,7 @@ package org.mapsforge.android.rendertheme;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Stack;
|
||||
import java.util.logging.Level;
|
||||
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.Caption;
|
||||
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.LineSymbol;
|
||||
import org.mapsforge.android.rendertheme.renderinstruction.PathText;
|
||||
import org.mapsforge.android.rendertheme.renderinstruction.RenderInstruction;
|
||||
import org.mapsforge.android.rendertheme.renderinstruction.Symbol;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.InputSource;
|
||||
@ -41,14 +44,23 @@ import org.xml.sax.helpers.DefaultHandler;
|
||||
* SAX2 handler to parse XML render theme files.
|
||||
*/
|
||||
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 {
|
||||
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_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: ";
|
||||
|
||||
/**
|
||||
@ -62,10 +74,12 @@ public class RenderThemeHandler extends DefaultHandler {
|
||||
* @throws IOException
|
||||
* 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 {
|
||||
RenderThemeHandler renderThemeHandler = new RenderThemeHandler();
|
||||
XMLReader xmlReader = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
|
||||
XMLReader xmlReader = SAXParserFactory.newInstance().newSAXParser()
|
||||
.getXMLReader();
|
||||
xmlReader.setContentHandler(renderThemeHandler);
|
||||
xmlReader.parse(new InputSource(inputStream));
|
||||
return renderThemeHandler.mRenderTheme;
|
||||
@ -83,7 +97,8 @@ public class RenderThemeHandler extends DefaultHandler {
|
||||
* @param attributeIndex
|
||||
* 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.append("unknown attribute in element ");
|
||||
stringBuilder.append(element);
|
||||
@ -110,6 +125,7 @@ public class RenderThemeHandler extends DefaultHandler {
|
||||
|
||||
mRenderTheme.setLevels(mLevel);
|
||||
mRenderTheme.complete();
|
||||
tmpStyleHash.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -131,8 +147,12 @@ public class RenderThemeHandler extends DefaultHandler {
|
||||
LOG.log(Level.SEVERE, null, exception);
|
||||
}
|
||||
|
||||
private static HashMap<String, RenderInstruction> tmpStyleHash = new HashMap<String, RenderInstruction>(
|
||||
10);
|
||||
|
||||
@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 {
|
||||
if (ELEMENT_NAME_RENDER_THEME.equals(localName)) {
|
||||
checkState(localName, Element.RENDER_THEME);
|
||||
@ -149,10 +169,53 @@ public class RenderThemeHandler extends DefaultHandler {
|
||||
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)) {
|
||||
checkState(localName, Element.RENDERING_INSTRUCTION);
|
||||
Area area = Area.create(localName, attributes, mLevel++);
|
||||
mRuleStack.peek().addRenderingInstruction(area);
|
||||
// mRuleStack.peek().addRenderingInstruction(area);
|
||||
mCurrentRule.addRenderingInstruction(area);
|
||||
}
|
||||
|
||||
else if ("caption".equals(localName)) {
|
||||
@ -169,17 +232,10 @@ public class RenderThemeHandler extends DefaultHandler {
|
||||
|
||||
else if ("line".equals(localName)) {
|
||||
checkState(localName, Element.RENDERING_INSTRUCTION);
|
||||
Line line = Line.create(localName, attributes, mLevel++);
|
||||
Line line = Line.create(null, localName, attributes, mLevel++, false);
|
||||
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)) {
|
||||
checkState(localName, Element.RENDERING_INSTRUCTION);
|
||||
LineSymbol lineSymbol = LineSymbol.create(localName, attributes);
|
||||
@ -198,7 +254,45 @@ public class RenderThemeHandler extends DefaultHandler {
|
||||
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);
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
@ -214,6 +308,7 @@ public class RenderThemeHandler extends DefaultHandler {
|
||||
}
|
||||
|
||||
private void checkElement(String elementName, Element element) throws SAXException {
|
||||
Element parentElement;
|
||||
switch (element) {
|
||||
case RENDER_THEME:
|
||||
if (!mElementStack.empty()) {
|
||||
@ -222,8 +317,16 @@ public class RenderThemeHandler extends DefaultHandler {
|
||||
return;
|
||||
|
||||
case RULE:
|
||||
Element parentElement = mElementStack.peek();
|
||||
if (parentElement != Element.RENDER_THEME && parentElement != Element.RULE) {
|
||||
parentElement = mElementStack.peek();
|
||||
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);
|
||||
}
|
||||
return;
|
||||
|
||||
@ -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 Pattern SPLIT_PATTERN = Pattern.compile("\\|");
|
||||
private static final String STRING_NEGATION = "~";
|
||||
private static final String STRING_EXCLUSIVE = "-";
|
||||
private static final String STRING_WILDCARD = "*";
|
||||
|
||||
private static Rule createRule(Stack<Rule> ruleStack, int element, String keys,
|
||||
@ -44,11 +45,18 @@ abstract class Rule {
|
||||
.split(values)));
|
||||
|
||||
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,
|
||||
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 valueMatcher = getValueMatcher(valueList);
|
||||
|
||||
@ -189,13 +197,14 @@ abstract class Rule {
|
||||
|
||||
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)) {
|
||||
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++)
|
||||
mSubRuleArray[i].matchNode(renderCallback, tags, zoomLevel);
|
||||
mSubRuleArray[i].matchNode(renderCallback, tags, zoomLevel, matchingList);
|
||||
|
||||
}
|
||||
}
|
||||
@ -220,14 +229,15 @@ abstract class Rule {
|
||||
MATCHERS_CACHE_VALUE.clear();
|
||||
|
||||
mRenderInstructionArray = new RenderInstruction[mRenderInstructions.size()];
|
||||
|
||||
for (int i = 0, n = mRenderInstructions.size(); i < n; i++)
|
||||
mRenderInstructionArray[i] = mRenderInstructions.get(i);
|
||||
mRenderInstructions.toArray(mRenderInstructionArray);
|
||||
// for (int i = 0, n = mRenderInstructions.size(); i < n; i++)
|
||||
// mRenderInstructionArray[i] = mRenderInstructions.get(i);
|
||||
|
||||
mSubRuleArray = new Rule[mSubRules.size()];
|
||||
mSubRules.toArray(mSubRuleArray);
|
||||
|
||||
for (int i = 0, n = mSubRules.size(); i < n; i++)
|
||||
mSubRuleArray[i] = mSubRules.get(i);
|
||||
// for (int i = 0, n = mSubRules.size(); i < n; i++)
|
||||
// mSubRuleArray[i] = mSubRules.get(i);
|
||||
|
||||
mRenderInstructions.clear();
|
||||
mRenderInstructions = null;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -132,11 +132,11 @@
|
||||
<xs:attribute name="src" type="tns:src" use="optional" />
|
||||
<xs:attribute name="stroke" type="tns:color" use="optional"
|
||||
default="#000000" />
|
||||
<xs:attribute name="stroke-width" type="tns:nonNegativeFloat"
|
||||
<xs:attribute name="width" type="tns:nonNegativeFloat"
|
||||
use="optional" default="0" />
|
||||
<xs:attribute name="stroke-dasharray" type="tns:strokeDasharray"
|
||||
use="optional" />
|
||||
<xs:attribute name="stroke-linecap" type="tns:cap" use="optional"
|
||||
<xs:attribute name="cap" type="tns:cap" use="optional"
|
||||
default="round" />
|
||||
<xs:attribute name="outline" type="xs:integer" use="optional"
|
||||
default="0" />
|
||||
@ -163,6 +163,7 @@
|
||||
</xs:complexType>
|
||||
|
||||
<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="dy" type="xs:float" use="optional"
|
||||
default="0" />
|
||||
@ -190,7 +191,7 @@
|
||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<!-- recursion to allow for nested rules -->
|
||||
<xs:element name="rule" type="tns:rule" />
|
||||
|
||||
|
||||
<xs:element name="area" type="tns:area" />
|
||||
<xs:element name="caption" type="tns:caption" />
|
||||
<xs:element name="circle" type="tns:circle" />
|
||||
@ -198,6 +199,7 @@
|
||||
<xs:element name="outline" type="tns:outline" />
|
||||
<xs:element name="lineSymbol" type="tns:lineSymbol" />
|
||||
<xs:element name="pathText" type="tns:pathText" />
|
||||
<xs:element name="stylePathText type="xs:string" />
|
||||
<xs:element name="symbol" type="tns:symbol" />
|
||||
</xs:choice>
|
||||
<xs:attribute name="e" type="tns:elementList" use="required" />
|
||||
@ -214,6 +216,12 @@
|
||||
|
||||
<!-- rendertheme element -->
|
||||
<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:element name="rule" type="tns:rule" />
|
||||
</xs:sequence>
|
||||
|
||||
@ -14,23 +14,17 @@
|
||||
*/
|
||||
package org.mapsforge.android.rendertheme.renderinstruction;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.mapsforge.android.rendertheme.IRenderCallback;
|
||||
import org.mapsforge.android.rendertheme.RenderThemeHandler;
|
||||
import org.mapsforge.core.Tag;
|
||||
import org.xml.sax.Attributes;
|
||||
|
||||
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.
|
||||
*/
|
||||
public final class Area implements RenderInstruction {
|
||||
public final class Area extends RenderInstruction {
|
||||
/**
|
||||
* @param elementName
|
||||
* the name of the XML element.
|
||||
@ -39,11 +33,8 @@ public final class Area implements RenderInstruction {
|
||||
* @param level
|
||||
* the drawing level of this instruction.
|
||||
* @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)
|
||||
throws IOException {
|
||||
public static Area create(String elementName, Attributes attributes, int level) {
|
||||
String src = null;
|
||||
int fill = Color.BLACK;
|
||||
int stroke = Color.TRANSPARENT;
|
||||
@ -51,12 +42,14 @@ public final class Area implements RenderInstruction {
|
||||
int fade = -1;
|
||||
int blend = -1;
|
||||
int blendFill = Color.BLACK;
|
||||
String style = null;
|
||||
|
||||
for (int i = 0; i < attributes.getLength(); ++i) {
|
||||
String name = attributes.getLocalName(i);
|
||||
String value = attributes.getValue(i);
|
||||
|
||||
if ("src".equals(name)) {
|
||||
if ("name".equals(name))
|
||||
style = value;
|
||||
else if ("src".equals(name)) {
|
||||
src = value;
|
||||
} else if ("fill".equals(name)) {
|
||||
fill = Color.parseColor(value);
|
||||
@ -76,7 +69,8 @@ public final class Area implements RenderInstruction {
|
||||
}
|
||||
|
||||
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) {
|
||||
@ -86,32 +80,38 @@ public final class Area implements RenderInstruction {
|
||||
}
|
||||
}
|
||||
|
||||
private Area(String src, int fill, int stroke, float strokeWidth, int fade,
|
||||
int level, int blend, int blendFill)
|
||||
throws IOException {
|
||||
private Area(String style, String src, int fill, int stroke, float strokeWidth,
|
||||
int fade, int level, int blend, int blendFill) {
|
||||
super();
|
||||
this.style = style;
|
||||
|
||||
if (fill == Color.TRANSPARENT) {
|
||||
paintFill = null;
|
||||
} else {
|
||||
paintFill = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
if (src != null) {
|
||||
Shader shader = BitmapUtils.createBitmapShader(src);
|
||||
paintFill.setShader(shader);
|
||||
}
|
||||
paintFill.setStyle(Style.FILL);
|
||||
paintFill.setColor(fill);
|
||||
paintFill.setStrokeCap(Cap.ROUND);
|
||||
}
|
||||
// if (fill == Color.TRANSPARENT) {
|
||||
// paintFill = null;
|
||||
// } else {
|
||||
// paintFill = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
// if (src != null) {
|
||||
// Shader shader = BitmapUtils.createBitmapShader(src);
|
||||
// paintFill.setShader(shader);
|
||||
// }
|
||||
// paintFill.setStyle(Style.FILL);
|
||||
// paintFill.setColor(fill);
|
||||
// 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) {
|
||||
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) {
|
||||
// stroke = null;
|
||||
// } else{
|
||||
// stroke = new Line()
|
||||
// }
|
||||
|
||||
color = new float[4];
|
||||
color[0] = (fill >> 16 & 0xff) / 255.0f;
|
||||
@ -135,47 +135,31 @@ public final class Area implements RenderInstruction {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderNode(IRenderCallback renderCallback, Tag[] tags) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderWay(IRenderCallback renderCallback, Tag[] tags) {
|
||||
if (paintFill != null) {
|
||||
renderCallback.renderArea(this);
|
||||
}
|
||||
renderCallback.renderArea(this, this.level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scaleStrokeWidth(float scaleFactor) {
|
||||
if (paintOutline != null) {
|
||||
paintOutline.setStrokeWidth(strokeWidth * scaleFactor);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scaleTextSize(float scaleFactor) {
|
||||
// do nothing
|
||||
}
|
||||
// @Override
|
||||
// public void scaleStrokeWidth(float scaleFactor) {
|
||||
// // if (paintOutline != null) {
|
||||
// // paintOutline.setStrokeWidth(strokeWidth * scaleFactor);
|
||||
// // }
|
||||
// }
|
||||
|
||||
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;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
||||
@ -12,17 +12,22 @@
|
||||
* 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;
|
||||
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 TextLayer {
|
||||
public ArrayList<TextItem> labels;
|
||||
|
||||
void addLabel(float x, float y, String text, Caption caption) {
|
||||
public class AreaLevel extends RenderInstruction {
|
||||
private final Area area;
|
||||
private final int level;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -32,7 +32,7 @@ import android.util.FloatMath;
|
||||
/**
|
||||
* Represents a text label on the map.
|
||||
*/
|
||||
public final class Caption implements RenderInstruction {
|
||||
public final class Caption extends RenderInstruction {
|
||||
/**
|
||||
* @param elementName
|
||||
* the name of the XML element.
|
||||
@ -130,11 +130,6 @@ public final class Caption implements RenderInstruction {
|
||||
fontDescent = FloatMath.ceil(Math.abs(fm.descent));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderNode(IRenderCallback renderCallback, Tag[] tags) {
|
||||
renderCallback.renderPointOfInterestCaption(this);
|
||||
@ -145,11 +140,6 @@ public final class Caption implements RenderInstruction {
|
||||
renderCallback.renderAreaCaption(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scaleStrokeWidth(float scaleFactor) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scaleTextSize(float scaleFactor) {
|
||||
paint.setTextSize(fontSize * scaleFactor);
|
||||
|
||||
@ -26,7 +26,7 @@ import android.graphics.Paint.Style;
|
||||
/**
|
||||
* Represents a round area on the map.
|
||||
*/
|
||||
public final class Circle implements RenderInstruction {
|
||||
public final class Circle extends RenderInstruction {
|
||||
/**
|
||||
* @param elementName
|
||||
* 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) {
|
||||
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) {
|
||||
throw new IllegalArgumentException("radius must not be negative: " + radius);
|
||||
} 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 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();
|
||||
|
||||
mRadius = radius.floatValue();
|
||||
@ -117,11 +120,6 @@ public final class Circle implements RenderInstruction {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderNode(IRenderCallback renderCallback, Tag[] tags) {
|
||||
if (mOutline != null) {
|
||||
@ -132,11 +130,6 @@ public final class Circle implements RenderInstruction {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderWay(IRenderCallback renderCallback, Tag[] tags) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scaleStrokeWidth(float scaleFactor) {
|
||||
if (mScaleRadius) {
|
||||
@ -146,9 +139,4 @@ public final class Circle implements RenderInstruction {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scaleTextSize(float scaleFactor) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,7 +14,6 @@
|
||||
*/
|
||||
package org.mapsforge.android.rendertheme.renderinstruction;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@ -24,73 +23,94 @@ import org.mapsforge.core.Tag;
|
||||
import org.xml.sax.Attributes;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.graphics.DashPathEffect;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Paint.Cap;
|
||||
import android.graphics.Paint.Style;
|
||||
import android.graphics.Shader;
|
||||
|
||||
/**
|
||||
* 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(",");
|
||||
|
||||
/**
|
||||
* @param line
|
||||
* ...
|
||||
* @param elementName
|
||||
* the name of the XML element.
|
||||
* @param attributes
|
||||
* the attributes of the XML element.
|
||||
* @param level
|
||||
* the drawing level of this instruction.
|
||||
* @param isOutline
|
||||
* ...
|
||||
* @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)
|
||||
throws IOException {
|
||||
public static Line create(Line line, String elementName, Attributes attributes,
|
||||
int level, boolean isOutline) {
|
||||
String src = null;
|
||||
int stroke = Color.BLACK;
|
||||
float strokeWidth = 0;
|
||||
float[] strokeDasharray = null;
|
||||
Cap strokeLinecap = Cap.ROUND;
|
||||
int outline = -1;
|
||||
int fade = -1;
|
||||
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) {
|
||||
String name = attributes.getLocalName(i);
|
||||
String value = attributes.getValue(i);
|
||||
|
||||
if ("src".equals(name)) {
|
||||
if ("name".equals(name))
|
||||
style = value;
|
||||
else if ("src".equals(name)) {
|
||||
src = value;
|
||||
} else if ("stroke".equals(name)) {
|
||||
stroke = Color.parseColor(value);
|
||||
} else if ("stroke-width".equals(name)) {
|
||||
} else if ("width".equals(name)) {
|
||||
strokeWidth = Float.parseFloat(value);
|
||||
} else if ("stroke-dasharray".equals(name)) {
|
||||
strokeDasharray = parseFloatArray(value);
|
||||
} else if ("stroke-linecap".equals(name)) {
|
||||
} else if ("cap".equals(name)) {
|
||||
strokeLinecap = Cap.valueOf(value.toUpperCase(Locale.ENGLISH));
|
||||
} else if ("outline".equals(name)) {
|
||||
outline = Integer.parseInt(value);
|
||||
} else if ("fade".equals(name)) {
|
||||
fade = Integer.parseInt(value);
|
||||
} else if ("fixed".equals(name)) {
|
||||
fixed = Boolean.parseBoolean(value);
|
||||
} else if ("blur".equals(name)) {
|
||||
blur = Float.parseFloat(value);
|
||||
} else if ("from".equals(name)) {
|
||||
} else {
|
||||
RenderThemeHandler.logUnknownAttribute(elementName, name, value, i);
|
||||
}
|
||||
}
|
||||
|
||||
validate(strokeWidth);
|
||||
return new Line(src, stroke, strokeWidth, strokeDasharray, strokeLinecap, level,
|
||||
outline, fixed, fade);
|
||||
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);
|
||||
|
||||
return new Line(style, src, stroke, strokeWidth, strokeDasharray, strokeLinecap,
|
||||
level, fixed, fade, blur, isOutline);
|
||||
}
|
||||
|
||||
private static void validate(float strokeWidth) {
|
||||
if (strokeWidth < 0) {
|
||||
throw new IllegalArgumentException("stroke-width must not be negative: "
|
||||
throw new IllegalArgumentException("width must not be negative: "
|
||||
+ 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;
|
||||
|
||||
private Line(String src, int stroke, float strokeWidth, float[] strokeDasharray,
|
||||
Cap strokeLinecap, int level,
|
||||
int outline, boolean fixed, int fade)
|
||||
throws IOException {
|
||||
public final String style;
|
||||
|
||||
public final Cap cap;
|
||||
|
||||
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();
|
||||
|
||||
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);
|
||||
|
||||
this.cap = strokeLinecap;
|
||||
|
||||
color = new float[4];
|
||||
color[0] = (stroke >> 16 & 0xff) / 255.0f;
|
||||
color[1] = (stroke >> 8 & 0xff) / 255.0f;
|
||||
color[2] = (stroke >> 0 & 0xff) / 255.0f;
|
||||
color[3] = (stroke >> 24 & 0xff) / 255.0f;
|
||||
|
||||
this.strokeWidth = strokeWidth;
|
||||
this.width = strokeWidth;
|
||||
this.level = level;
|
||||
this.outline = outline;
|
||||
this.outline = isOutline;
|
||||
this.fixed = fixed;
|
||||
this.blur = blur;
|
||||
this.fade = fade;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
// do nothing
|
||||
}
|
||||
private Line(Line line, String style, String src, int stroke, float strokeWidth,
|
||||
float[] strokeDasharray, Cap strokeLinecap, int level, boolean fixed,
|
||||
int fade, float blur, boolean isOutline) {
|
||||
super();
|
||||
|
||||
@Override
|
||||
public void renderNode(IRenderCallback renderCallback, Tag[] tags) {
|
||||
// do nothing
|
||||
this.style = style;
|
||||
|
||||
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
|
||||
public void renderWay(IRenderCallback renderCallback, Tag[] tags) {
|
||||
// renderCallback.renderWay(mPaint, mLevel, mColor, mStrokeWidth, mRound, mOutline);
|
||||
renderCallback.renderWay(this);
|
||||
renderCallback.renderWay(this, level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scaleStrokeWidth(float scaleFactor) {
|
||||
paint.setStrokeWidth(strokeWidth * scaleFactor);
|
||||
}
|
||||
// @Override
|
||||
// public void scaleStrokeWidth(float scaleFactor) {
|
||||
// paint.setStrokeWidth(strokeWidth * scaleFactor);
|
||||
// }
|
||||
|
||||
@Override
|
||||
public void scaleTextSize(float scaleFactor) {
|
||||
// do nothing
|
||||
public int getLevel() {
|
||||
return this.level;
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,7 +26,7 @@ import android.graphics.Bitmap;
|
||||
/**
|
||||
* Represents an icon along a polyline on the map.
|
||||
*/
|
||||
public final class LineSymbol implements RenderInstruction {
|
||||
public final class LineSymbol extends RenderInstruction {
|
||||
/**
|
||||
* @param elementName
|
||||
* the name of the XML element.
|
||||
@ -36,7 +36,8 @@ public final class LineSymbol implements RenderInstruction {
|
||||
* @throws IOException
|
||||
* 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;
|
||||
boolean alignCenter = false;
|
||||
boolean repeat = false;
|
||||
@ -62,7 +63,8 @@ public final class LineSymbol implements RenderInstruction {
|
||||
|
||||
private static void validate(String elementName, String src) {
|
||||
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 boolean mRepeat;
|
||||
|
||||
private LineSymbol(String src, boolean alignCenter, boolean repeat) throws IOException {
|
||||
private LineSymbol(String src, boolean alignCenter, boolean repeat)
|
||||
throws IOException {
|
||||
super();
|
||||
|
||||
mBitmap = BitmapUtils.createBitmap(src);
|
||||
@ -83,23 +86,8 @@ public final class LineSymbol implements RenderInstruction {
|
||||
mBitmap.recycle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderNode(IRenderCallback renderCallback, Tag[] tags) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderWay(IRenderCallback renderCallback, Tag[] tags) {
|
||||
renderCallback.renderWaySymbol(mBitmap, mAlignCenter, mRepeat);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scaleStrokeWidth(float scaleFactor) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scaleTextSize(float scaleFactor) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,13 +24,15 @@ import org.xml.sax.Attributes;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Paint.Align;
|
||||
import android.graphics.Paint.FontMetrics;
|
||||
import android.graphics.Paint.Style;
|
||||
import android.graphics.Typeface;
|
||||
import android.util.FloatMath;
|
||||
|
||||
/**
|
||||
* Represents a text along a polyline on the map.
|
||||
*/
|
||||
public final class PathText implements RenderInstruction {
|
||||
public final class PathText extends RenderInstruction {
|
||||
/**
|
||||
* @param elementName
|
||||
* the name of the XML element.
|
||||
@ -46,12 +48,14 @@ public final class PathText implements RenderInstruction {
|
||||
int fill = Color.BLACK;
|
||||
int stroke = Color.BLACK;
|
||||
float strokeWidth = 0;
|
||||
String style = null;
|
||||
|
||||
for (int i = 0; i < attributes.getLength(); ++i) {
|
||||
String name = attributes.getLocalName(i);
|
||||
String value = attributes.getValue(i);
|
||||
|
||||
if ("k".equals(name)) {
|
||||
if ("name".equals(name))
|
||||
style = value;
|
||||
else if ("k".equals(name)) {
|
||||
textKey = TextKey.getInstance(value);
|
||||
} else if ("font-family".equals(name)) {
|
||||
fontFamily = FontFamily.valueOf(value.toUpperCase(Locale.ENGLISH));
|
||||
@ -72,67 +76,69 @@ public final class PathText implements RenderInstruction {
|
||||
|
||||
validate(elementName, textKey, fontSize, strokeWidth);
|
||||
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) {
|
||||
throw new IllegalArgumentException("missing attribute k for element: " + elementName);
|
||||
throw new IllegalArgumentException("missing attribute k for element: "
|
||||
+ elementName);
|
||||
} 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) {
|
||||
throw new IllegalArgumentException("stroke-width must not be negative: " + strokeWidth);
|
||||
throw new IllegalArgumentException("stroke-width must not be negative: "
|
||||
+ strokeWidth);
|
||||
}
|
||||
}
|
||||
|
||||
private final float mFontSize;
|
||||
private final Paint mPaint;
|
||||
private final Paint mStroke;
|
||||
private final String mTextKey;
|
||||
public final float fontSize;
|
||||
public final Paint paint;
|
||||
public Paint stroke;
|
||||
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();
|
||||
|
||||
mTextKey = textKey;
|
||||
this.style = style;
|
||||
|
||||
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
mPaint.setTextAlign(Align.CENTER);
|
||||
mPaint.setTypeface(typeface);
|
||||
mPaint.setColor(fill);
|
||||
this.textKey = textKey;
|
||||
|
||||
mStroke = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
mStroke.setStyle(Style.STROKE);
|
||||
mStroke.setTextAlign(Align.CENTER);
|
||||
mStroke.setTypeface(typeface);
|
||||
mStroke.setColor(stroke);
|
||||
mStroke.setStrokeWidth(strokeWidth);
|
||||
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
paint.setTextAlign(Align.CENTER);
|
||||
paint.setTypeface(typeface);
|
||||
paint.setColor(fill);
|
||||
|
||||
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
|
||||
public void destroy() {
|
||||
// do nothing
|
||||
}
|
||||
this.fontSize = fontSize;
|
||||
|
||||
@Override
|
||||
public void renderNode(IRenderCallback renderCallback, Tag[] tags) {
|
||||
// do nothing
|
||||
paint.setTextSize(fontSize);
|
||||
stroke.setTextSize(fontSize);
|
||||
|
||||
FontMetrics fm = paint.getFontMetrics();
|
||||
fontHeight = FloatMath.ceil(Math.abs(fm.bottom) + Math.abs(fm.top));
|
||||
fontDescent = FloatMath.ceil(Math.abs(fm.descent));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderWay(IRenderCallback renderCallback, Tag[] tags) {
|
||||
renderCallback.renderWayText(mTextKey, mPaint, mStroke);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scaleStrokeWidth(float scaleFactor) {
|
||||
// do nothing
|
||||
renderCallback.renderWayText(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scaleTextSize(float scaleFactor) {
|
||||
mPaint.setTextSize(mFontSize * scaleFactor);
|
||||
mStroke.setTextSize(mFontSize * scaleFactor);
|
||||
paint.setTextSize(fontSize * scaleFactor);
|
||||
stroke.setTextSize(fontSize * scaleFactor);
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,11 +20,12 @@ import org.mapsforge.core.Tag;
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
void destroy();
|
||||
public void destroy() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param renderCallback
|
||||
@ -32,7 +33,8 @@ public interface RenderInstruction {
|
||||
* @param tags
|
||||
* the tags of the node.
|
||||
*/
|
||||
void renderNode(IRenderCallback renderCallback, Tag[] tags);
|
||||
public void renderNode(IRenderCallback renderCallback, Tag[] tags) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param renderCallback
|
||||
@ -40,7 +42,8 @@ public interface RenderInstruction {
|
||||
* @param tags
|
||||
* 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.
|
||||
@ -48,7 +51,8 @@ public interface RenderInstruction {
|
||||
* @param scaleFactor
|
||||
* 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.
|
||||
@ -56,5 +60,6 @@ public interface RenderInstruction {
|
||||
* @param scaleFactor
|
||||
* the factor by which the text size should be scaled.
|
||||
*/
|
||||
void scaleTextSize(float scaleFactor);
|
||||
public void scaleTextSize(float scaleFactor) {
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,7 +26,7 @@ import android.graphics.Bitmap;
|
||||
/**
|
||||
* Represents an icon on the map.
|
||||
*/
|
||||
public final class Symbol implements RenderInstruction {
|
||||
public final class Symbol extends RenderInstruction {
|
||||
/**
|
||||
* @param elementName
|
||||
* the name of the XML element.
|
||||
@ -36,7 +36,8 @@ public final class Symbol implements RenderInstruction {
|
||||
* @throws IOException
|
||||
* 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;
|
||||
|
||||
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) {
|
||||
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) {
|
||||
renderCallback.renderAreaSymbol(mBitmap);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scaleStrokeWidth(float scaleFactor) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scaleTextSize(float scaleFactor) {
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,6 +24,7 @@ import org.mapsforge.android.rendertheme.RenderTheme;
|
||||
import org.mapsforge.android.rendertheme.renderinstruction.Area;
|
||||
import org.mapsforge.android.rendertheme.renderinstruction.Caption;
|
||||
import org.mapsforge.android.rendertheme.renderinstruction.Line;
|
||||
import org.mapsforge.android.rendertheme.renderinstruction.PathText;
|
||||
import org.mapsforge.core.Tag;
|
||||
import org.mapsforge.core.Tile;
|
||||
import org.mapsforge.database.IMapDatabase;
|
||||
@ -414,24 +415,24 @@ public class MapGenerator implements IMapGenerator, IRenderCallback,
|
||||
private List<ShapeContainer> mCurLevelContainer2;
|
||||
|
||||
@Override
|
||||
public void renderWay(Line line) {
|
||||
List<ShapeContainer> c = mDrawingLayer.add(line.level, mWayDataContainer,
|
||||
line.paint);
|
||||
|
||||
if (mCurLevelContainer1 == null)
|
||||
mCurLevelContainer1 = c;
|
||||
else if (mCurLevelContainer2 == null)
|
||||
mCurLevelContainer2 = c;
|
||||
public void renderWay(Line line, int level) {
|
||||
// List<ShapeContainer> c = mDrawingLayer.add(level, mWayDataContainer,
|
||||
// line.paint);
|
||||
//
|
||||
// if (mCurLevelContainer1 == null)
|
||||
// mCurLevelContainer1 = c;
|
||||
// else if (mCurLevelContainer2 == null)
|
||||
// mCurLevelContainer2 = c;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderArea(Area area) {
|
||||
if (area.paintFill != null)
|
||||
mCurLevelContainer1 = mDrawingLayer.add(area.level, mWayDataContainer,
|
||||
area.paintFill);
|
||||
if (area.paintOutline != null)
|
||||
mCurLevelContainer1 = mDrawingLayer.add(area.level, mWayDataContainer,
|
||||
area.paintOutline);
|
||||
public void renderArea(Area area, int level) {
|
||||
// if (area.paintFill != null)
|
||||
// mCurLevelContainer1 = mDrawingLayer.add(level, mWayDataContainer,
|
||||
// area.paintFill);
|
||||
// if (area.paintOutline != null)
|
||||
// mCurLevelContainer1 = mDrawingLayer.add(level, mWayDataContainer,
|
||||
// area.paintOutline);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -443,7 +444,7 @@ public class MapGenerator implements IMapGenerator, IRenderCallback,
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderWayText(String textKey, Paint paint, Paint outline) {
|
||||
public void renderWayText(PathText pathText) {
|
||||
// if (mWayDataContainer.textPos[0] >= 0)
|
||||
// WayDecorator.renderText(this, paint, outline, mCoords, mWayDataContainer, mWayNames);
|
||||
}
|
||||
|
||||
@ -33,6 +33,7 @@ import org.mapsforge.android.mapgenerator.JobParameters;
|
||||
import org.mapsforge.android.mapgenerator.MapGeneratorJob;
|
||||
import org.mapsforge.android.mapgenerator.TileCacheKey;
|
||||
import org.mapsforge.android.mapgenerator.TileDistanceSort;
|
||||
import org.mapsforge.android.rendertheme.RenderTheme;
|
||||
import org.mapsforge.android.utils.GlUtils;
|
||||
import org.mapsforge.core.MapPosition;
|
||||
import org.mapsforge.core.MercatorProjection;
|
||||
@ -213,7 +214,7 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
|
||||
newTiles[tiles++] = tile;
|
||||
|
||||
if (!tile.isReady || (tile.getScale() != scale)) {
|
||||
tile.isLoading = true;
|
||||
// tile.isLoading = true;
|
||||
// approximation for TileScheduler
|
||||
if (tileY < tileTop || tileY > tileBottom || tileX < tileLeft
|
||||
|| tileX > tileRight)
|
||||
@ -494,12 +495,6 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
|
||||
}
|
||||
}
|
||||
}
|
||||
// FIXME
|
||||
// if (loadedTexture) {
|
||||
// synchronized (mMapWorker) {
|
||||
// mMapWorker.notify();
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -588,4 +583,10 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
|
||||
public IMapGenerator createMapGenerator() {
|
||||
return new MapGenerator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRenderTheme(RenderTheme t) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,7 +38,8 @@ final class WayDecorator {
|
||||
*/
|
||||
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) {
|
||||
int skipPixels = SEGMENT_SAFETY_DISTANCE;
|
||||
|
||||
@ -68,9 +69,11 @@ final class WayDecorator {
|
||||
// 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));
|
||||
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
|
||||
if (!repeatSymbol) {
|
||||
@ -145,7 +148,8 @@ final class WayDecorator {
|
||||
} else if ((currentY - nextY) == 0)
|
||||
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
|
||||
if (diff >= 0.2 || diff <= -0.2)
|
||||
@ -210,7 +214,7 @@ final class WayDecorator {
|
||||
y2 = previousY;
|
||||
}
|
||||
|
||||
// estimate position of test on path
|
||||
// estimate position of text on path
|
||||
width = (x2 - x1) / 2;
|
||||
x2 = x2 - (int) (width - s * width);
|
||||
x1 = x1 + (int) (width - s * width);
|
||||
@ -234,7 +238,8 @@ final class WayDecorator {
|
||||
break;
|
||||
|
||||
// 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;
|
||||
break;
|
||||
}
|
||||
@ -244,7 +249,8 @@ final class WayDecorator {
|
||||
short top2 = (wtc2.y1 < wtc2.y2 ? wtc2.y1 : wtc2.y2);
|
||||
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)) {
|
||||
intersects = true;
|
||||
@ -260,7 +266,8 @@ final class WayDecorator {
|
||||
}
|
||||
|
||||
Log.d("mapsforge", "add " + text + " " + first + " " + last);
|
||||
WayTextContainer wtc = new WayTextContainer(first, last, wayDataContainer, text,
|
||||
WayTextContainer wtc = new WayTextContainer(first, last,
|
||||
wayDataContainer, text,
|
||||
paint);
|
||||
wtc.x1 = (short) x1;
|
||||
wtc.y1 = (short) y1;
|
||||
@ -272,7 +279,8 @@ final class WayDecorator {
|
||||
containerSize++;
|
||||
|
||||
if (outline != null) {
|
||||
wayNames.add(new WayTextContainer(first, last, wayDataContainer, text, outline));
|
||||
wayNames.add(new WayTextContainer(first, last, wayDataContainer,
|
||||
text, outline));
|
||||
containerSize++;
|
||||
}
|
||||
// 500 ??? how big is a tile?!
|
||||
|
||||
@ -29,7 +29,7 @@ public class GlConfigChooser implements GLSurfaceView.EGLConfigChooser {
|
||||
EGL10.EGL_GREEN_SIZE, 6,
|
||||
EGL10.EGL_BLUE_SIZE, 5,
|
||||
EGL10.EGL_ALPHA_SIZE, 0,
|
||||
EGL10.EGL_DEPTH_SIZE, 0,
|
||||
EGL10.EGL_DEPTH_SIZE, 16,
|
||||
// Requires that setEGLContextClientVersion(2) is called on the view.
|
||||
EGL10.EGL_RENDERABLE_TYPE, 4 /* EGL_OPENGL_ES2_BIT */,
|
||||
// EGL10.EGL_SAMPLE_BUFFERS, 1 /* true */,
|
||||
@ -50,7 +50,7 @@ public class GlConfigChooser implements GLSurfaceView.EGLConfigChooser {
|
||||
EGL10.EGL_GREEN_SIZE, 6,
|
||||
EGL10.EGL_BLUE_SIZE, 5,
|
||||
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_STENCIL_SIZE, 4,
|
||||
EGL10.EGL_NONE };
|
||||
@ -93,7 +93,10 @@ public class GlConfigChooser implements GLSurfaceView.EGLConfigChooser {
|
||||
// // else
|
||||
// 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;
|
||||
// break;
|
||||
// }
|
||||
|
||||
@ -92,9 +92,23 @@ public class Tag {
|
||||
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) {
|
||||
this.key = (key == null ? null : key);
|
||||
this.value = (value == null ? null : value);
|
||||
if (intern) {
|
||||
this.key = (key == null ? null : key.intern());
|
||||
this.value = (value == null ? null : value.intern());
|
||||
}
|
||||
else {
|
||||
this.key = (key == null ? null : key);
|
||||
this.value = (value == null ? null : value);
|
||||
}
|
||||
this.hashCodeValue = calculateHashCode();
|
||||
}
|
||||
|
||||
|
||||
@ -60,6 +60,8 @@ public class Tile {
|
||||
*/
|
||||
public final long pixelY;
|
||||
|
||||
public volatile boolean isCanceled;
|
||||
|
||||
/**
|
||||
* @param tileX
|
||||
* the X number of the tile.
|
||||
|
||||
@ -251,7 +251,7 @@ public class MapDatabase implements IMapDatabase {
|
||||
|
||||
@Override
|
||||
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;
|
||||
|
||||
// check if the way has a name
|
||||
if ((featureByte & WAY_FEATURE_NAME) != 0)
|
||||
if ((featureByte & WAY_FEATURE_NAME) != 0) {
|
||||
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
|
||||
textPos[0] = -1;
|
||||
|
||||
// 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();
|
||||
|
||||
}
|
||||
else
|
||||
textPos[1] = -1;
|
||||
|
||||
|
||||
@ -19,10 +19,10 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.SocketException;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.util.HashMap;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpResponse;
|
||||
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.SchemeRegistry;
|
||||
import org.apache.http.impl.client.DefaultHttpClient;
|
||||
import org.apache.http.message.BasicHeader;
|
||||
import org.apache.http.params.BasicHttpParams;
|
||||
import org.apache.http.params.HttpConnectionParams;
|
||||
import org.apache.http.params.HttpParams;
|
||||
@ -41,7 +40,6 @@ import org.mapsforge.core.BoundingBox;
|
||||
import org.mapsforge.core.GeoPoint;
|
||||
import org.mapsforge.core.Tag;
|
||||
import org.mapsforge.core.Tile;
|
||||
import org.mapsforge.core.WebMercator;
|
||||
import org.mapsforge.database.FileOpenResult;
|
||||
import org.mapsforge.database.IMapDatabase;
|
||||
import org.mapsforge.database.IMapDatabaseCallback;
|
||||
@ -60,45 +58,62 @@ public class MapDatabase implements IMapDatabase {
|
||||
private static final MapFileInfo mMapInfo =
|
||||
new MapFileInfo(new BoundingBox(-180, -90, 180, 90),
|
||||
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 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/gis2/%d/%d/%d.osmtile";
|
||||
private static final Header encodingHeader =
|
||||
new BasicHeader("Accept-Encoding", "gzip");
|
||||
// private static final Header encodingHeader =
|
||||
// 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 HttpClient mClient;
|
||||
private IMapDatabaseCallback mMapGenerator;
|
||||
private float mScaleFactor;
|
||||
private HttpGet mRequest = null;
|
||||
private Tile mTile;
|
||||
|
||||
@Override
|
||||
public QueryResult executeQuery(Tile tile, IMapDatabaseCallback mapDatabaseCallback) {
|
||||
mCanceled = false;
|
||||
// just used for debugging ....
|
||||
mTile = tile;
|
||||
// Log.d(TAG, "get tile >> : " + tile);
|
||||
|
||||
String url = String.format(URL, Integer.valueOf(tile.zoomLevel),
|
||||
Long.valueOf(tile.tileX), Long.valueOf(tile.tileY));
|
||||
|
||||
HttpGet getRequest = new HttpGet(url);
|
||||
getRequest.addHeader(encodingHeader);
|
||||
|
||||
mRequest = getRequest;
|
||||
mMapGenerator = mapDatabaseCallback;
|
||||
mCurTagCnt = 0;
|
||||
|
||||
// using variable coordinate scalefactor to take advantage of varint
|
||||
mScaleFactor = 1 / 100f;
|
||||
if (tile.zoomLevel < 12)
|
||||
mScaleFactor = (float) Math.pow(2, (12 - tile.zoomLevel)) / 100f;
|
||||
mScaleFactor = REF_TILE_SIZE / Tile.TILE_SIZE;
|
||||
|
||||
try {
|
||||
HttpResponse response = mClient.execute(getRequest);
|
||||
@ -110,17 +125,24 @@ public class MapDatabase implements IMapDatabase {
|
||||
entity.consumeContent();
|
||||
return QueryResult.FAILED;
|
||||
}
|
||||
|
||||
if (mTile.isCanceled) {
|
||||
Log.d(TAG, "1 loading canceled " + mTile);
|
||||
entity.consumeContent();
|
||||
return QueryResult.FAILED;
|
||||
}
|
||||
|
||||
InputStream is = null;
|
||||
GZIPInputStream zis = null;
|
||||
// GZIPInputStream zis = null;
|
||||
try {
|
||||
is = entity.getContent();
|
||||
zis = new GZIPInputStream(is);
|
||||
// zis = new GZIPInputStream(is);
|
||||
|
||||
decode(zis);
|
||||
decode(is);
|
||||
|
||||
} finally {
|
||||
if (zis != null)
|
||||
zis.close();
|
||||
// if (zis != null)
|
||||
// zis.close();
|
||||
if (is != null)
|
||||
is.close();
|
||||
entity.consumeContent();
|
||||
@ -137,6 +159,12 @@ public class MapDatabase implements IMapDatabase {
|
||||
return QueryResult.FAILED;
|
||||
}
|
||||
mRequest = null;
|
||||
|
||||
if (mTile.isCanceled) {
|
||||
Log.d(TAG, "2 loading canceled " + mTile);
|
||||
return QueryResult.FAILED;
|
||||
}
|
||||
|
||||
// Log.d(TAG, "get tile << : " + tile);
|
||||
|
||||
return QueryResult.SUCCESS;
|
||||
@ -144,7 +172,7 @@ public class MapDatabase implements IMapDatabase {
|
||||
|
||||
@Override
|
||||
public String getMapProjection() {
|
||||
return WebMercator.NAME;
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -158,8 +186,6 @@ public class MapDatabase implements IMapDatabase {
|
||||
}
|
||||
|
||||
private void createClient() {
|
||||
// mClient = AndroidHttpClient.newInstance("Android");
|
||||
|
||||
mOpenFile = true;
|
||||
HttpParams params = new BasicHttpParams();
|
||||
HttpConnectionParams.setStaleCheckingEnabled(params, false);
|
||||
@ -193,7 +219,8 @@ public class MapDatabase implements IMapDatabase {
|
||||
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 int bufferPos;
|
||||
@ -261,20 +288,25 @@ public class MapDatabase implements IMapDatabase {
|
||||
String tagString = decodeString();
|
||||
|
||||
Tag tag = tagHash.get(tagString);
|
||||
|
||||
if (tag == null) {
|
||||
// Log.d(TAG, "tag:" + tagString);
|
||||
if (tagString.equals("name="))
|
||||
tag = new Tag(tagString, false);
|
||||
if (tagString.startsWith(Tag.TAG_KEY_NAME))
|
||||
tag = new Tag(Tag.TAG_KEY_NAME, tagString.substring(5), false);
|
||||
else
|
||||
tag = new Tag(tagString);
|
||||
|
||||
tagHash.put(tagString, tag);
|
||||
}
|
||||
// FIXME ...
|
||||
if (mCurTagCnt < 250)
|
||||
curTags[mCurTagCnt++] = tag;
|
||||
|
||||
//
|
||||
// FIXME ...
|
||||
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;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -285,7 +317,7 @@ public class MapDatabase implements IMapDatabase {
|
||||
int indexCnt = 0;
|
||||
int tagCnt = 0;
|
||||
int coordCnt = 0;
|
||||
int layer = 0;
|
||||
int layer = 5;
|
||||
Tag[] tags = null;
|
||||
short[] index = null;
|
||||
|
||||
@ -294,7 +326,6 @@ public class MapDatabase implements IMapDatabase {
|
||||
|
||||
while (bytesRead < end) {
|
||||
// read tag and wire type
|
||||
|
||||
int val = decodeVarint32();
|
||||
if (val == 0)
|
||||
break;
|
||||
@ -350,18 +381,10 @@ public class MapDatabase implements IMapDatabase {
|
||||
}
|
||||
|
||||
float[] coords = tmpCoords;
|
||||
int pos = 0;
|
||||
|
||||
float z = mScaleFactor;
|
||||
for (int j = 0, m = indexCnt; j < m; j++) {
|
||||
float lastX = 0;
|
||||
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;
|
||||
}
|
||||
}
|
||||
// FIXME !!!!!
|
||||
if (layer == 0)
|
||||
layer = 5;
|
||||
|
||||
mMapGenerator.renderWay((byte) layer, tags, coords, index, polygon);
|
||||
return true;
|
||||
@ -429,12 +452,20 @@ public class MapDatabase implements IMapDatabase {
|
||||
readBuffer(bytes);
|
||||
int cnt = 0;
|
||||
int end = bufferPos + bytes;
|
||||
|
||||
float scale = mScaleFactor;
|
||||
// read repeated sint32
|
||||
int lastX = 0;
|
||||
int lastY = 0;
|
||||
while (bufferPos < end && cnt < numNodes) {
|
||||
float lon = decodeZigZag32(decodeVarint32()) * mScaleFactor;
|
||||
float lat = decodeZigZag32(decodeVarint32()) * mScaleFactor;
|
||||
mMapGenerator.renderPointOfInterest(layer, lat, lon, tags);
|
||||
int lon = decodeZigZag32(decodeVarint32()); // * mScaleFactor;
|
||||
int lat = decodeZigZag32(decodeVarint32()); // * mScaleFactor;
|
||||
lastX = lon + lastX;
|
||||
lastY = lat + lastY;
|
||||
|
||||
mMapGenerator.renderPointOfInterest(layer,
|
||||
lastY / scale,
|
||||
lastX / scale,
|
||||
tags);
|
||||
cnt += 2;
|
||||
}
|
||||
return cnt;
|
||||
@ -443,13 +474,6 @@ public class MapDatabase implements IMapDatabase {
|
||||
private int MAX_WAY_COORDS = 32768;
|
||||
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 {
|
||||
int bytes = decodeVarint32();
|
||||
|
||||
@ -457,33 +481,45 @@ public class MapDatabase implements IMapDatabase {
|
||||
|
||||
int cnt = 0;
|
||||
int end = bytesRead + bytes;
|
||||
int max = curTags.length;
|
||||
int max = mCurTagCnt;
|
||||
|
||||
while (bytesRead < end) {
|
||||
int tagNum = decodeVarint32();
|
||||
|
||||
if (tagNum < 0 || cnt == tagCnt)
|
||||
continue;
|
||||
|
||||
if (tagNum < 0 || cnt == tagCnt) {
|
||||
Log.d(TAG, "NULL TAG: " + mTile + " invalid tag:" + tagNum + " "
|
||||
+ tagCnt + "/" + cnt);
|
||||
break;
|
||||
}
|
||||
if (tagNum < Tags.MAX)
|
||||
tags[cnt++] = Tags.tags[tagNum];
|
||||
else {
|
||||
tagNum -= Tags.LIMIT;
|
||||
|
||||
if (tagNum >= 0 && tagNum < max) {
|
||||
// Log.d(TAG, "variable tag: " + 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;
|
||||
}
|
||||
|
||||
private short[] mIndices = new short[10];
|
||||
|
||||
private short[] decodeWayIndices(int indexCnt) throws IOException {
|
||||
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 end = bytesRead + bytes;
|
||||
@ -495,6 +531,9 @@ public class MapDatabase implements IMapDatabase {
|
||||
// else DEBUG...
|
||||
|
||||
}
|
||||
|
||||
index[indexCnt] = -1;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
@ -514,67 +553,78 @@ public class MapDatabase implements IMapDatabase {
|
||||
int cnt = 0;
|
||||
int result;
|
||||
|
||||
int x, lastX = 0;
|
||||
int y, lastY = 0;
|
||||
boolean even = true;
|
||||
|
||||
float scale = mScaleFactor;
|
||||
|
||||
// read repeated sint32
|
||||
while (pos < end) {
|
||||
if (cnt >= MAX_WAY_COORDS) {
|
||||
Log.d(TAG, "increase way coord buffer " + mTile);
|
||||
|
||||
MAX_WAY_COORDS += 128;
|
||||
float[] tmp = new float[MAX_WAY_COORDS];
|
||||
System.arraycopy(coords, 0, tmp, 0, cnt);
|
||||
tmpCoords = coords = tmp;
|
||||
}
|
||||
|
||||
byte tmp = buf[pos++];
|
||||
if (tmp >= 0) {
|
||||
result = tmp;
|
||||
if (buf[pos] >= 0) {
|
||||
result = buf[pos++];
|
||||
} 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 {
|
||||
result = tmp & 0x7f;
|
||||
if ((tmp = buf[pos++]) >= 0) {
|
||||
result |= tmp << 7;
|
||||
} else {
|
||||
result |= (tmp & 0x7f) << 7;
|
||||
if ((tmp = buf[pos++]) >= 0) {
|
||||
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;
|
||||
result = buf[pos] & 0x7f
|
||||
| buf[pos + 1] << 7
|
||||
| buf[pos + 2] << 14
|
||||
| buf[pos + 3] << 21
|
||||
| buf[pos + 4] << 28;
|
||||
pos += 5;
|
||||
|
||||
if (tmp < 0) {
|
||||
int i = 0;
|
||||
// Discard upper 32 bits.
|
||||
while (i++ < 5) {
|
||||
if (buf[pos++] >= 0)
|
||||
break;
|
||||
}
|
||||
Log.d(TAG, "5 Stuffs too large " + mTile);
|
||||
|
||||
if (i == 5)
|
||||
// FIXME throw some poo
|
||||
Log.d(TAG, "EEK malformedVarint");
|
||||
}
|
||||
}
|
||||
if (buf[pos + 4] < 0) {
|
||||
Log.d(TAG, "Stuffs too large ...");
|
||||
int i = 0;
|
||||
while (i++ < 5) {
|
||||
if (buf[pos++] >= 0)
|
||||
break;
|
||||
}
|
||||
if (i == 5)
|
||||
throw new IOException("EEEK malformed varInt");
|
||||
}
|
||||
}
|
||||
coords[cnt++] = (result >>> 1) ^ -(result & 1);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
bufferPos = pos;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -589,9 +639,6 @@ public class MapDatabase implements IMapDatabase {
|
||||
}
|
||||
bufferSize = len;
|
||||
bufferPos = 0;
|
||||
|
||||
// Log.d(TAG, "pos " + bufferPos + ", size " + bufferSize + ", read "
|
||||
// + bytesRead);
|
||||
}
|
||||
|
||||
private void readBuffer(int size) throws IOException {
|
||||
@ -612,6 +659,10 @@ public class MapDatabase implements IMapDatabase {
|
||||
}
|
||||
|
||||
while ((bufferSize - bufferPos) < size) {
|
||||
if (mTile.isCanceled) {
|
||||
throw new IOException("canceled " + mTile);
|
||||
}
|
||||
|
||||
// read until requested size is available in buffer
|
||||
int len = inputStream.read(buffer, bufferSize, BUFFER_SIZE - bufferSize);
|
||||
if (len < 0) {
|
||||
@ -621,13 +672,6 @@ public class MapDatabase implements IMapDatabase {
|
||||
|
||||
bufferSize += len;
|
||||
|
||||
// if (len == 0)
|
||||
// try {
|
||||
// wait(50);
|
||||
// } catch (InterruptedException e) {
|
||||
// // just waiting for data
|
||||
// }
|
||||
|
||||
if (mCanceled)
|
||||
throw new IOException("... canceld?");
|
||||
}
|
||||
@ -637,6 +681,17 @@ public class MapDatabase implements IMapDatabase {
|
||||
// + ", 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: */
|
||||
|
||||
// Protocol Buffers - Google's data interchange format
|
||||
@ -727,17 +782,4 @@ public class MapDatabase implements IMapDatabase {
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -45,14 +45,14 @@ import android.util.Log;
|
||||
public class MapDatabase implements IMapDatabase {
|
||||
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 mIndexPos = 0;
|
||||
private float[] mCoords = new float[100000];
|
||||
private short[] mIndex = new short[10000];
|
||||
private float[] mCoords;
|
||||
private short[] mIndex;
|
||||
|
||||
private Tag[] mTags;
|
||||
|
||||
@ -71,7 +71,7 @@ public class MapDatabase implements IMapDatabase {
|
||||
|
||||
private boolean connect() {
|
||||
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();
|
||||
dbOpts.setProperty("user", "osm");
|
||||
@ -212,6 +212,10 @@ public class MapDatabase implements IMapDatabase {
|
||||
@Override
|
||||
public FileOpenResult openFile(File mapFile) {
|
||||
mOpenFile = true;
|
||||
if (mCoords == null) {
|
||||
mCoords = new float[100000];
|
||||
mIndex = new short[100000];
|
||||
}
|
||||
return new FileOpenResult();
|
||||
}
|
||||
|
||||
@ -226,6 +230,8 @@ public class MapDatabase implements IMapDatabase {
|
||||
connection = null;
|
||||
}
|
||||
}
|
||||
mCoords = null;
|
||||
mIndex = null;
|
||||
mOpenFile = false;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user