- 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.IMapGenerator;
|
||||||
import org.mapsforge.android.mapgenerator.MapGeneratorJob;
|
import org.mapsforge.android.mapgenerator.MapGeneratorJob;
|
||||||
|
import org.mapsforge.android.rendertheme.RenderTheme;
|
||||||
|
|
||||||
import android.opengl.GLSurfaceView;
|
import android.opengl.GLSurfaceView;
|
||||||
|
|
||||||
@ -46,4 +47,6 @@ public interface IMapRenderer extends GLSurfaceView.Renderer {
|
|||||||
public void redrawTiles(boolean clear);
|
public void redrawTiles(boolean clear);
|
||||||
|
|
||||||
public IMapGenerator createMapGenerator();
|
public IMapGenerator createMapGenerator();
|
||||||
|
|
||||||
|
public void setRenderTheme(RenderTheme t);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -496,6 +496,7 @@ public class MapView extends GLSurfaceView {
|
|||||||
*
|
*
|
||||||
* @param internalRenderTheme
|
* @param internalRenderTheme
|
||||||
* the internal rendering theme.
|
* the internal rendering theme.
|
||||||
|
* @return ...
|
||||||
* @throws IllegalArgumentException
|
* @throws IllegalArgumentException
|
||||||
* if the supplied internalRenderTheme is null.
|
* if the supplied internalRenderTheme is null.
|
||||||
*/
|
*/
|
||||||
@ -538,6 +539,7 @@ public class MapView extends GLSurfaceView {
|
|||||||
try {
|
try {
|
||||||
inputStream = theme.getRenderThemeAsStream();
|
inputStream = theme.getRenderThemeAsStream();
|
||||||
RenderTheme t = RenderThemeHandler.getRenderTheme(inputStream);
|
RenderTheme t = RenderThemeHandler.getRenderTheme(inputStream);
|
||||||
|
mMapRenderer.setRenderTheme(t);
|
||||||
mMapWorkers[0].getMapGenerator().setRenderTheme(t);
|
mMapWorkers[0].getMapGenerator().setRenderTheme(t);
|
||||||
return true;
|
return true;
|
||||||
} catch (ParserConfigurationException e) {
|
} catch (ParserConfigurationException e) {
|
||||||
|
|||||||
@ -14,21 +14,23 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapsforge.android.glrenderer;
|
package org.mapsforge.android.glrenderer;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import org.mapsforge.android.mapgenerator.MapTile;
|
import org.mapsforge.android.mapgenerator.MapTile;
|
||||||
import org.mapsforge.core.Tile;
|
import org.mapsforge.core.Tile;
|
||||||
|
|
||||||
class GLMapTile extends MapTile {
|
class GLMapTile extends MapTile {
|
||||||
|
long lastDraw = 0;
|
||||||
|
|
||||||
|
VertexBufferObject vbo;
|
||||||
|
|
||||||
|
// polygonOffset is always 8
|
||||||
|
int lineOffset;
|
||||||
|
|
||||||
VertexBufferObject lineVBO;
|
|
||||||
VertexBufferObject polygonVBO;
|
|
||||||
TextTexture texture;
|
TextTexture texture;
|
||||||
|
|
||||||
LineLayer lineLayers;
|
LineLayer lineLayers;
|
||||||
PolygonLayer polygonLayers;
|
PolygonLayer polygonLayers;
|
||||||
|
|
||||||
ArrayList<TextItem> labels;
|
TextItem labels;
|
||||||
|
|
||||||
boolean newData;
|
boolean newData;
|
||||||
boolean loading;
|
boolean loading;
|
||||||
@ -37,9 +39,6 @@ class GLMapTile extends MapTile {
|
|||||||
final long x;
|
final long x;
|
||||||
final long y;
|
final long y;
|
||||||
|
|
||||||
// scissor coordinates
|
|
||||||
int sx, sy, sw, sh;
|
|
||||||
|
|
||||||
final GLMapTile[] child = { null, null, null, null };
|
final GLMapTile[] child = { null, null, null, null };
|
||||||
GLMapTile parent;
|
GLMapTile parent;
|
||||||
|
|
||||||
|
|||||||
@ -15,38 +15,35 @@
|
|||||||
package org.mapsforge.android.glrenderer;
|
package org.mapsforge.android.glrenderer;
|
||||||
|
|
||||||
import org.mapsforge.android.rendertheme.renderinstruction.Line;
|
import org.mapsforge.android.rendertheme.renderinstruction.Line;
|
||||||
|
import org.mapsforge.core.Tile;
|
||||||
|
|
||||||
|
import android.graphics.Paint.Cap;
|
||||||
import android.util.FloatMath;
|
import android.util.FloatMath;
|
||||||
|
|
||||||
class LineLayer {
|
class LineLayer {
|
||||||
|
|
||||||
private static final float SCALE_FACTOR = 16;
|
private static final float S = MapRenderer.COORD_MULTIPLIER;
|
||||||
|
private static final float S1000 = 1000;
|
||||||
Line line;
|
|
||||||
|
|
||||||
LineLayer next;
|
LineLayer next;
|
||||||
LineLayer outlines;
|
LineLayer outlines;
|
||||||
|
|
||||||
|
Line line;
|
||||||
float width;
|
float width;
|
||||||
boolean isOutline;
|
boolean isOutline;
|
||||||
|
int layer;
|
||||||
|
|
||||||
ShortItem pool;
|
ShortItem pool;
|
||||||
protected ShortItem curItem;
|
protected ShortItem curItem;
|
||||||
int verticesCnt;
|
int verticesCnt;
|
||||||
int offset;
|
int offset;
|
||||||
|
short[] mVertex;
|
||||||
|
|
||||||
final int layer;
|
LineLayer(int layer, Line line, float width, boolean outline) {
|
||||||
|
|
||||||
LineLayer(int layer, Line line, boolean outline) {
|
|
||||||
this.layer = layer;
|
this.layer = layer;
|
||||||
|
this.width = width;
|
||||||
this.line = line;
|
this.line = line;
|
||||||
this.isOutline = outline;
|
this.isOutline = outline;
|
||||||
|
|
||||||
if (!outline) {
|
|
||||||
curItem = ShortPool.get();
|
|
||||||
pool = curItem;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void addOutline(LineLayer link) {
|
void addOutline(LineLayer link) {
|
||||||
@ -58,45 +55,82 @@ class LineLayer {
|
|||||||
outlines = link;
|
outlines = link;
|
||||||
}
|
}
|
||||||
|
|
||||||
short[] getNextItem() {
|
private static ShortItem addTwoVertex(short[] vertex, ShortItem item) {
|
||||||
curItem.used = ShortItem.SIZE;
|
ShortItem it = item;
|
||||||
|
|
||||||
curItem.next = ShortPool.get();
|
if (it.used + 6 >= ShortItem.SIZE) {
|
||||||
curItem = curItem.next;
|
|
||||||
|
|
||||||
return curItem.vertices;
|
if (it.used == ShortItem.SIZE) {
|
||||||
|
it.next = ShortPool.get();
|
||||||
|
it = it.next;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
System.arraycopy(vertex, 0, it.vertices, it.used, 6);
|
||||||
|
it.used += 6;
|
||||||
|
|
||||||
|
it.next = ShortPool.get();
|
||||||
|
it = it.next;
|
||||||
|
|
||||||
|
System.arraycopy(vertex, 6, it.vertices, it.used, 6);
|
||||||
|
it.used += 6;
|
||||||
|
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
System.arraycopy(vertex, 0, it.vertices, it.used, 12);
|
||||||
|
it.used += 12;
|
||||||
|
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ShortItem addVertex(short[] vertex, ShortItem item) {
|
||||||
|
ShortItem it = item;
|
||||||
|
|
||||||
|
if (it.used == ShortItem.SIZE) {
|
||||||
|
it.next = ShortPool.get();
|
||||||
|
it = it.next;
|
||||||
|
}
|
||||||
|
|
||||||
|
System.arraycopy(vertex, 0, it.vertices, it.used, 6);
|
||||||
|
it.used += 6;
|
||||||
|
|
||||||
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* line extrusion is based on code from GLMap (https://github.com/olofsj/GLMap/) by olofsj
|
* line extrusion is based on code from GLMap (https://github.com/olofsj/GLMap/) by olofsj -- need some way to know
|
||||||
|
* how the road connects to set the ending angles
|
||||||
*/
|
*/
|
||||||
void addLine(float[] pointArray, int pos, int length, float w, boolean capRound) {
|
void addLine(float[] pointArray, int pos, int length) {
|
||||||
float x, y, nextX, nextY, prevX, prevY, ux, uy, vx, vy, wx, wy;
|
float x, y, nextX, nextY, prevX, prevY, ux, uy, vx, vy, wx, wy;
|
||||||
float a;
|
float a;
|
||||||
int pointPos = pos;
|
int pointPos = pos;
|
||||||
boolean rounded = capRound;
|
boolean rounded = false;
|
||||||
width = w;// * SCALE_FACTOR;
|
boolean squared = false;
|
||||||
if (w < 0.5)
|
|
||||||
rounded = false;
|
if (line.cap == Cap.ROUND)
|
||||||
|
rounded = true;
|
||||||
|
else if (line.cap == Cap.SQUARE)
|
||||||
|
squared = true;
|
||||||
|
|
||||||
|
if (pool == null) {
|
||||||
|
curItem = ShortPool.get();
|
||||||
|
pool = curItem;
|
||||||
|
|
||||||
|
mVertex = new short[12];
|
||||||
|
}
|
||||||
|
|
||||||
// amount of vertices used
|
// amount of vertices used
|
||||||
verticesCnt += length + (rounded ? 6 : 2);
|
verticesCnt += length + (rounded ? 6 : 2);
|
||||||
|
|
||||||
int MAX = PoolItem.SIZE;
|
ShortItem si = curItem;
|
||||||
|
|
||||||
short[] curVertices = curItem.vertices;
|
x = pointArray[pointPos++];
|
||||||
int vertexPos = curItem.used;
|
y = pointArray[pointPos++];
|
||||||
|
|
||||||
if (vertexPos == MAX) {
|
nextX = pointArray[pointPos++];
|
||||||
curVertices = getNextItem();
|
nextY = pointArray[pointPos++];
|
||||||
vertexPos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
x = pointArray[pointPos++];// * SCALE_FACTOR;
|
|
||||||
y = pointArray[pointPos++];// * SCALE_FACTOR;
|
|
||||||
|
|
||||||
nextX = pointArray[pointPos++];// * SCALE_FACTOR;
|
|
||||||
nextY = pointArray[pointPos++];// * SCALE_FACTOR;
|
|
||||||
|
|
||||||
// Calculate triangle corners for the given width
|
// Calculate triangle corners for the given width
|
||||||
vx = nextX - x;
|
vx = nextX - x;
|
||||||
@ -110,109 +144,83 @@ class LineLayer {
|
|||||||
ux = -vy;
|
ux = -vy;
|
||||||
uy = vx;
|
uy = vx;
|
||||||
|
|
||||||
float uxw = ux * w;
|
float uxw = ux;
|
||||||
float uyw = uy * w;
|
float uyw = uy;
|
||||||
|
|
||||||
float vxw = vx * w;
|
float vxw = vx;
|
||||||
float vyw = vy * w;
|
float vyw = vy;
|
||||||
|
int tsize = Tile.TILE_SIZE;
|
||||||
|
|
||||||
// boolean outside = (x <= 0 || x >= Tile.TILE_SIZE || y <= 0 || y >= Tile.TILE_SIZE)
|
short v[] = mVertex;
|
||||||
// && (x - vxw <= 0 || x - vxw >= Tile.TILE_SIZE || y - vyw <= 0 || y - vyw >= Tile.TILE_SIZE);
|
|
||||||
|
v[0] = (short) (x * S);
|
||||||
|
v[1] = (short) (y * S);
|
||||||
|
|
||||||
|
boolean outside = (x <= 0 || x >= tsize || y <= 0 || y >= tsize)
|
||||||
|
&& (x - vxw <= 0 || x - vxw >= tsize || y - vyw <= 0 || y - vyw >= tsize);
|
||||||
|
|
||||||
boolean outside = false;
|
|
||||||
if (rounded && !outside) {
|
if (rounded && !outside) {
|
||||||
|
v[2] = (short) ((uxw - vxw) * S1000);
|
||||||
|
v[3] = (short) ((uyw - vyw) * S1000);
|
||||||
|
v[4] = -1;
|
||||||
|
v[5] = 1;
|
||||||
|
si = addVertex(v, si);
|
||||||
|
si = addVertex(v, si);
|
||||||
|
|
||||||
// Add the first point twice to be able to draw with GL_TRIANGLE_STRIP
|
v[2] = (short) (-(uxw + vxw) * S1000);
|
||||||
|
v[3] = (short) (-(uyw + vyw) * S1000);
|
||||||
curVertices[vertexPos++] = (short) ((x + uxw - vxw) * SCALE_FACTOR);
|
v[4] = 1;
|
||||||
curVertices[vertexPos++] = (short) ((y + uyw - vyw) * SCALE_FACTOR);
|
v[5] = 1;
|
||||||
curVertices[vertexPos++] = -1;
|
si = addVertex(v, si);
|
||||||
curVertices[vertexPos++] = 1;
|
|
||||||
|
|
||||||
if (vertexPos == MAX) {
|
|
||||||
curVertices = getNextItem();
|
|
||||||
vertexPos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
curVertices[vertexPos++] = (short) ((x + uxw - vxw) * SCALE_FACTOR);
|
|
||||||
curVertices[vertexPos++] = (short) ((y + uyw - vyw) * SCALE_FACTOR);
|
|
||||||
curVertices[vertexPos++] = -1;
|
|
||||||
curVertices[vertexPos++] = 1;
|
|
||||||
|
|
||||||
if (vertexPos == MAX) {
|
|
||||||
curVertices = getNextItem();
|
|
||||||
vertexPos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
curVertices[vertexPos++] = (short) ((x - uxw - vxw) * SCALE_FACTOR);
|
|
||||||
curVertices[vertexPos++] = (short) ((y - uyw - vyw) * SCALE_FACTOR);
|
|
||||||
curVertices[vertexPos++] = 1;
|
|
||||||
curVertices[vertexPos++] = 1;
|
|
||||||
|
|
||||||
if (vertexPos == MAX) {
|
|
||||||
curVertices = getNextItem();
|
|
||||||
vertexPos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start of line
|
// Start of line
|
||||||
curVertices[vertexPos++] = (short) ((x + uxw) * SCALE_FACTOR);
|
v[2] = (short) ((uxw) * S1000);
|
||||||
curVertices[vertexPos++] = (short) ((y + uyw) * SCALE_FACTOR);
|
v[3] = (short) ((uyw) * S1000);
|
||||||
curVertices[vertexPos++] = -1;
|
v[4] = -1;
|
||||||
curVertices[vertexPos++] = 0;
|
v[5] = 0;
|
||||||
|
si = addVertex(v, si);
|
||||||
|
|
||||||
if (vertexPos == MAX) {
|
v[2] = (short) ((-uxw) * S1000);
|
||||||
curVertices = getNextItem();
|
v[3] = (short) ((-uyw) * S1000);
|
||||||
vertexPos = 0;
|
v[4] = 1;
|
||||||
}
|
v[5] = 0;
|
||||||
|
si = addVertex(v, si);
|
||||||
curVertices[vertexPos++] = (short) ((x - uxw) * SCALE_FACTOR);
|
|
||||||
curVertices[vertexPos++] = (short) ((y - uyw) * SCALE_FACTOR);
|
|
||||||
curVertices[vertexPos++] = 1;
|
|
||||||
curVertices[vertexPos++] = 0;
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// outside means line is probably clipped
|
// outside means line is probably clipped
|
||||||
// TODO should align ending with tile boundary
|
// TODO should align ending with tile boundary
|
||||||
// for now, just extend the line a little
|
// for now, just extend the line a little
|
||||||
if (!outside) {
|
|
||||||
|
if (squared) {
|
||||||
|
vxw = 0;
|
||||||
|
vyw = 0;
|
||||||
|
} else if (!outside) {
|
||||||
vxw *= 0.5;
|
vxw *= 0.5;
|
||||||
vyw *= 0.5;
|
vyw *= 0.5;
|
||||||
}
|
}
|
||||||
if (rounded) {
|
|
||||||
|
if (rounded)
|
||||||
verticesCnt -= 2;
|
verticesCnt -= 2;
|
||||||
}
|
|
||||||
// Add the first point twice to be able to draw with GL_TRIANGLE_STRIP
|
// Add the first point twice to be able to draw with GL_TRIANGLE_STRIP
|
||||||
curVertices[vertexPos++] = (short) ((x + uxw - vxw) * SCALE_FACTOR);
|
v[2] = (short) ((uxw - vxw) * S1000);
|
||||||
curVertices[vertexPos++] = (short) ((y + uyw - vyw) * SCALE_FACTOR);
|
v[3] = (short) ((uyw - vyw) * S1000);
|
||||||
curVertices[vertexPos++] = -1;
|
v[4] = -1;
|
||||||
curVertices[vertexPos++] = 0;
|
v[5] = 0;
|
||||||
|
si = addVertex(v, si);
|
||||||
|
si = addVertex(v, si);
|
||||||
|
|
||||||
if (vertexPos == MAX) {
|
v[2] = (short) (-(uxw + vxw) * S1000);
|
||||||
curVertices = getNextItem();
|
v[3] = (short) (-(uyw + vyw) * S1000);
|
||||||
vertexPos = 0;
|
v[4] = 1;
|
||||||
}
|
v[5] = 0;
|
||||||
|
si = addVertex(v, si);
|
||||||
curVertices[vertexPos++] = (short) ((x + uxw - vxw) * SCALE_FACTOR);
|
|
||||||
curVertices[vertexPos++] = (short) ((y + uyw - vyw) * SCALE_FACTOR);
|
|
||||||
curVertices[vertexPos++] = -1;
|
|
||||||
curVertices[vertexPos++] = 0;
|
|
||||||
|
|
||||||
if (vertexPos == MAX) {
|
|
||||||
curVertices = getNextItem();
|
|
||||||
vertexPos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
curVertices[vertexPos++] = (short) ((x - uxw - vxw) * SCALE_FACTOR);
|
|
||||||
curVertices[vertexPos++] = (short) ((y - uyw - vyw) * SCALE_FACTOR);
|
|
||||||
curVertices[vertexPos++] = 1;
|
|
||||||
curVertices[vertexPos++] = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
prevX = x;
|
prevX = x;
|
||||||
prevY = y;
|
prevY = y;
|
||||||
x = nextX;
|
x = nextX;
|
||||||
y = nextY;
|
y = nextY;
|
||||||
// boolean flipped = false;
|
|
||||||
|
|
||||||
for (; pointPos < pos + length;) {
|
for (; pointPos < pos + length;) {
|
||||||
nextX = pointArray[pointPos++];
|
nextX = pointArray[pointPos++];
|
||||||
@ -235,58 +243,40 @@ class LineLayer {
|
|||||||
// Sum of these two vectors points
|
// Sum of these two vectors points
|
||||||
ux = vx + wx;
|
ux = vx + wx;
|
||||||
uy = vy + wy;
|
uy = vy + wy;
|
||||||
|
|
||||||
a = -wy * ux + wx * uy;
|
a = -wy * ux + wx * uy;
|
||||||
|
|
||||||
if ((a < 0.1 && a > -0.1)) {
|
// boolean split = false;
|
||||||
// Almost straight, use normal vector
|
if (a < 0.1f && a > -0.1f) {
|
||||||
|
// Almost straight or miter goes to infinity, use normal vector
|
||||||
ux = -wy;
|
ux = -wy;
|
||||||
uy = wx;
|
uy = wx;
|
||||||
} else {
|
} else {
|
||||||
ux = (ux / a);
|
ux = (ux / a);
|
||||||
uy = (uy / a);
|
uy = (uy / a);
|
||||||
|
|
||||||
if (ux > 2 || uy > 2 || ux < -2 || uy < -2) {
|
if (ux > 2.0f || ux < -2.0f || uy > 2.0f || uy < -2.0f) {
|
||||||
ux = -wy;
|
ux = -wy;
|
||||||
uy = wx;
|
uy = wx;
|
||||||
|
|
||||||
// ux = vx + wx;
|
|
||||||
// uy = vy + wy;
|
|
||||||
// // Normalize u, and project normal vector onto this
|
|
||||||
// double c = Math.sqrt(ux * ux + uy * uy);
|
|
||||||
// if (a < 0) {
|
|
||||||
// ux = (float) -(ux / c);
|
|
||||||
// uy = (float) -(uy / c);
|
|
||||||
// }
|
|
||||||
// else {
|
|
||||||
// ux = (float) (ux / c);
|
|
||||||
// uy = (float) (uy / c);
|
|
||||||
// }
|
|
||||||
// flipped = flipped ? false : true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uxw = ux * w;
|
uxw = ux * S1000;
|
||||||
uyw = uy * w;
|
uyw = uy * S1000;
|
||||||
|
|
||||||
if (vertexPos == MAX) {
|
v[6] = v[0] = (short) (x * S);
|
||||||
curVertices = getNextItem();
|
v[7] = v[1] = (short) (y * S);
|
||||||
vertexPos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
curVertices[vertexPos++] = (short) ((x + uxw) * SCALE_FACTOR);
|
v[2] = (short) uxw;
|
||||||
curVertices[vertexPos++] = (short) ((y + uyw) * SCALE_FACTOR);
|
v[3] = (short) uyw;
|
||||||
curVertices[vertexPos++] = -1;
|
v[4] = -1;
|
||||||
curVertices[vertexPos++] = 0;
|
v[5] = 0;
|
||||||
|
|
||||||
if (vertexPos == MAX) {
|
v[8] = (short) -uxw;
|
||||||
curVertices = getNextItem();
|
v[9] = (short) -uyw;
|
||||||
vertexPos = 0;
|
v[10] = 1;
|
||||||
}
|
v[11] = 0;
|
||||||
|
si = addTwoVertex(v, si);
|
||||||
curVertices[vertexPos++] = (short) ((x - uxw) * SCALE_FACTOR);
|
|
||||||
curVertices[vertexPos++] = (short) ((y - uyw) * SCALE_FACTOR);
|
|
||||||
curVertices[vertexPos++] = 1;
|
|
||||||
curVertices[vertexPos++] = 0;
|
|
||||||
|
|
||||||
prevX = x;
|
prevX = x;
|
||||||
prevY = y;
|
prevY = y;
|
||||||
@ -305,105 +295,71 @@ class LineLayer {
|
|||||||
ux = vy;
|
ux = vy;
|
||||||
uy = -vx;
|
uy = -vx;
|
||||||
|
|
||||||
uxw = ux * w;
|
uxw = ux;
|
||||||
uyw = uy * w;
|
uyw = uy;
|
||||||
|
|
||||||
vxw = vx * w;
|
vxw = vx;
|
||||||
vyw = vy * w;
|
vyw = vy;
|
||||||
|
|
||||||
// outside = (x <= 0 || x >= Tile.TILE_SIZE || y <= 0 || y >= Tile.TILE_SIZE)
|
outside = (x <= 0 || x >= tsize || y <= 0 || y >= tsize)
|
||||||
// && (x - vxw <= 0 || x - vxw >= Tile.TILE_SIZE || y - vyw <= 0 || y - vyw >= Tile.TILE_SIZE);
|
&& (x - vxw <= 0 || x - vxw >= tsize || y - vyw <= 0 || y - vyw >= tsize);
|
||||||
|
|
||||||
if (vertexPos == MAX) {
|
v[0] = (short) (x * S);
|
||||||
curVertices = getNextItem();
|
v[1] = (short) (y * S);
|
||||||
vertexPos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rounded && !outside) {
|
if (rounded && !outside) {
|
||||||
curVertices[vertexPos++] = (short) ((x + uxw) * SCALE_FACTOR);
|
v[2] = (short) ((uxw) * S1000);
|
||||||
curVertices[vertexPos++] = (short) ((y + uyw) * SCALE_FACTOR);
|
v[3] = (short) ((uyw) * S1000);
|
||||||
curVertices[vertexPos++] = -1;
|
v[4] = -1;
|
||||||
curVertices[vertexPos++] = 0;
|
v[5] = 0;
|
||||||
|
si = addVertex(v, si);
|
||||||
|
|
||||||
if (vertexPos == MAX) {
|
v[2] = (short) ((-uxw) * S1000);
|
||||||
curVertices = getNextItem();
|
v[3] = (short) ((-uyw) * S1000);
|
||||||
vertexPos = 0;
|
v[4] = 1;
|
||||||
}
|
v[5] = 0;
|
||||||
|
si = addVertex(v, si);
|
||||||
curVertices[vertexPos++] = (short) ((x - uxw) * SCALE_FACTOR);
|
|
||||||
curVertices[vertexPos++] = (short) ((y - uyw) * SCALE_FACTOR);
|
|
||||||
curVertices[vertexPos++] = 1;
|
|
||||||
curVertices[vertexPos++] = 0;
|
|
||||||
|
|
||||||
if (vertexPos == MAX) {
|
|
||||||
curVertices = getNextItem();
|
|
||||||
vertexPos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For rounded line edges
|
// For rounded line edges
|
||||||
curVertices[vertexPos++] = (short) ((x + uxw - vxw) * SCALE_FACTOR);
|
v[2] = (short) ((uxw - vxw) * S1000);
|
||||||
curVertices[vertexPos++] = (short) ((y + uyw - vyw) * SCALE_FACTOR);
|
v[3] = (short) ((uyw - vyw) * S1000);
|
||||||
curVertices[vertexPos++] = -1;
|
v[4] = -1;
|
||||||
curVertices[vertexPos++] = -1;
|
v[5] = -1;
|
||||||
|
si = addVertex(v, si);
|
||||||
|
|
||||||
if (vertexPos == MAX) {
|
v[2] = (short) (-(uxw + vxw) * S1000);
|
||||||
curVertices = getNextItem();
|
v[3] = (short) (-(uyw + vyw) * S1000);
|
||||||
vertexPos = 0;
|
v[4] = 1;
|
||||||
}
|
v[5] = -1;
|
||||||
|
si = addVertex(v, si);
|
||||||
// Add the last vertex twice to be able to draw with GL_TRIANGLE_STRIP
|
si = addVertex(v, si);
|
||||||
curVertices[vertexPos++] = (short) ((x - uxw - vxw) * SCALE_FACTOR);
|
|
||||||
curVertices[vertexPos++] = (short) ((y - uyw - vyw) * SCALE_FACTOR);
|
|
||||||
curVertices[vertexPos++] = 1;
|
|
||||||
curVertices[vertexPos++] = -1;
|
|
||||||
|
|
||||||
if (vertexPos == MAX) {
|
|
||||||
curVertices = getNextItem();
|
|
||||||
vertexPos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
curVertices[vertexPos++] = (short) ((x - uxw - vxw) * SCALE_FACTOR);
|
|
||||||
curVertices[vertexPos++] = (short) ((y - uyw - vyw) * SCALE_FACTOR);
|
|
||||||
curVertices[vertexPos++] = 1;
|
|
||||||
curVertices[vertexPos++] = -1;
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (!outside) {
|
if (squared) {
|
||||||
|
vxw = 0;
|
||||||
|
vyw = 0;
|
||||||
|
} else if (!outside) {
|
||||||
vxw *= 0.5;
|
vxw *= 0.5;
|
||||||
vyw *= 0.5;
|
vyw *= 0.5;
|
||||||
}
|
}
|
||||||
if (rounded) {
|
|
||||||
|
if (rounded)
|
||||||
verticesCnt -= 2;
|
verticesCnt -= 2;
|
||||||
}
|
|
||||||
|
|
||||||
curVertices[vertexPos++] = (short) ((x + uxw) * SCALE_FACTOR);
|
v[2] = (short) ((uxw) * S1000);
|
||||||
curVertices[vertexPos++] = (short) ((y + uyw) * SCALE_FACTOR);
|
v[3] = (short) ((uyw) * S1000);
|
||||||
curVertices[vertexPos++] = -1;
|
v[4] = -1;
|
||||||
curVertices[vertexPos++] = 0;
|
v[5] = 0;
|
||||||
|
si = addVertex(v, si);
|
||||||
if (vertexPos == MAX) {
|
|
||||||
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 + 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;
|
package org.mapsforge.android.glrenderer;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import static android.opengl.GLES20.GL_TRIANGLE_STRIP;
|
||||||
import java.nio.ByteOrder;
|
import static android.opengl.GLES20.glDisableVertexAttribArray;
|
||||||
|
import static android.opengl.GLES20.glDrawArrays;
|
||||||
|
import static android.opengl.GLES20.glEnableVertexAttribArray;
|
||||||
|
import static android.opengl.GLES20.glGetAttribLocation;
|
||||||
|
import static android.opengl.GLES20.glGetUniformLocation;
|
||||||
|
import static android.opengl.GLES20.glUniform4f;
|
||||||
|
import static android.opengl.GLES20.glUniform4fv;
|
||||||
|
import static android.opengl.GLES20.glUniformMatrix4fv;
|
||||||
|
import static android.opengl.GLES20.glUseProgram;
|
||||||
|
import static android.opengl.GLES20.glVertexAttribPointer;
|
||||||
|
|
||||||
import java.nio.ShortBuffer;
|
import java.nio.ShortBuffer;
|
||||||
|
|
||||||
|
import org.mapsforge.android.rendertheme.renderinstruction.Line;
|
||||||
|
import org.mapsforge.android.utils.GlUtils;
|
||||||
|
|
||||||
|
import android.opengl.GLES20;
|
||||||
|
import android.util.FloatMath;
|
||||||
|
|
||||||
class LineLayers {
|
class LineLayers {
|
||||||
private static int NUM_VERTEX_FLOATS = 4;
|
private static int NUM_VERTEX_SHORTS = 6;
|
||||||
|
|
||||||
// static FloatBuffer compileLayerData(LineLayer layers, FloatBuffer buf) {
|
private static final int LINE_VERTICES_DATA_POS_OFFSET = 0;
|
||||||
// FloatBuffer fbuf = buf;
|
private static final int LINE_VERTICES_DATA_TEX_OFFSET = 8;
|
||||||
// int size = 0;
|
|
||||||
//
|
|
||||||
// for (LineLayer l = layers; l != null; l = l.next)
|
|
||||||
// size += l.verticesCnt;
|
|
||||||
//
|
|
||||||
// size *= NUM_VERTEX_FLOATS;
|
|
||||||
//
|
|
||||||
// if (buf == null || buf.capacity() < size) {
|
|
||||||
// ByteBuffer bbuf = ByteBuffer.allocateDirect(size * 4).order(
|
|
||||||
// ByteOrder.nativeOrder());
|
|
||||||
// fbuf = bbuf.asFloatBuffer();
|
|
||||||
// } else {
|
|
||||||
// fbuf.clear();
|
|
||||||
// }
|
|
||||||
// int pos = 0;
|
|
||||||
//
|
|
||||||
// PoolItem last = null, items = null;
|
|
||||||
//
|
|
||||||
// for (LineLayer l = layers; l != null; l = l.next) {
|
|
||||||
// if (l.isOutline)
|
|
||||||
// continue;
|
|
||||||
//
|
|
||||||
// for (PoolItem item = l.pool; item != null; item = item.next) {
|
|
||||||
// fbuf.put(item.vertices, 0, item.used);
|
|
||||||
// last = item;
|
|
||||||
// }
|
|
||||||
// l.offset = pos;
|
|
||||||
// pos += l.verticesCnt;
|
|
||||||
//
|
|
||||||
// if (last != null) {
|
|
||||||
// last.next = items;
|
|
||||||
// items = l.pool;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// l.pool = null;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// VertexPool.add(items);
|
|
||||||
//
|
|
||||||
// fbuf.flip();
|
|
||||||
//
|
|
||||||
// return fbuf;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// static ShortBuffer compileLayerData(LineLayer layers, ShortBuffer buf) {
|
|
||||||
// int size = 0;
|
|
||||||
// ShortBuffer sbuf = buf;
|
|
||||||
//
|
|
||||||
// for (LineLayer l = layers; l != null; l = l.next)
|
|
||||||
// size += l.verticesCnt;
|
|
||||||
//
|
|
||||||
// size *= NUM_VERTEX_FLOATS;
|
|
||||||
//
|
|
||||||
// if (buf == null || buf.capacity() < size) {
|
|
||||||
// ByteBuffer bbuf = ByteBuffer.allocateDirect(size * 2).order(
|
|
||||||
// ByteOrder.nativeOrder());
|
|
||||||
// sbuf = bbuf.asShortBuffer();
|
|
||||||
// } else {
|
|
||||||
// sbuf.clear();
|
|
||||||
// }
|
|
||||||
// int pos = 0;
|
|
||||||
//
|
|
||||||
// short[] data = new short[PoolItem.SIZE];
|
|
||||||
//
|
|
||||||
// PoolItem last = null, items = null;
|
|
||||||
//
|
|
||||||
// for (LineLayer l = layers; l != null; l = l.next) {
|
|
||||||
// if (l.isOutline)
|
|
||||||
// continue;
|
|
||||||
//
|
|
||||||
// for (PoolItem item = l.pool; item != null; item = item.next) {
|
|
||||||
// PoolItem.toHalfFloat(item, data);
|
|
||||||
// sbuf.put(data, 0, item.used);
|
|
||||||
// last = item;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// l.offset = pos;
|
|
||||||
// pos += l.verticesCnt;
|
|
||||||
//
|
|
||||||
// if (last != null) {
|
|
||||||
// last.next = items;
|
|
||||||
// items = l.pool;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// l.pool = null;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// VertexPool.add(items);
|
|
||||||
//
|
|
||||||
// sbuf.flip();
|
|
||||||
//
|
|
||||||
// return sbuf;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// static void clear(LineLayer layer) {
|
|
||||||
// for (LineLayer l = layer; l != null; l = l.next) {
|
|
||||||
// if (l.pool != null)
|
|
||||||
// VertexPool.add(l.pool);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
static ShortBuffer compileLayerData(LineLayer layers, ShortBuffer buf) {
|
// shader handles
|
||||||
|
private static int lineProgram;
|
||||||
|
private static int hLineVertexPosition;
|
||||||
|
private static int hLineTexturePosition;
|
||||||
|
private static int hLineColor;
|
||||||
|
private static int hLineMatrix;
|
||||||
|
private static int hLineScale;
|
||||||
|
private static int hLineWidth;
|
||||||
|
|
||||||
|
static boolean init() {
|
||||||
|
lineProgram = GlUtils.createProgram(Shaders.lineVertexShader,
|
||||||
|
Shaders.lineFragmentShader);
|
||||||
|
if (lineProgram == 0) {
|
||||||
|
// Log.e(TAG, "Could not create line program.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
hLineMatrix = glGetUniformLocation(lineProgram, "mvp");
|
||||||
|
hLineScale = glGetUniformLocation(lineProgram, "u_wscale");
|
||||||
|
hLineWidth = glGetUniformLocation(lineProgram, "u_width");
|
||||||
|
hLineColor = glGetUniformLocation(lineProgram, "u_color");
|
||||||
|
hLineVertexPosition = GLES20.glGetAttribLocation(lineProgram, "a_position");
|
||||||
|
hLineTexturePosition = glGetAttribLocation(lineProgram, "a_st");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static LineLayer drawLines(GLMapTile tile, LineLayer layer, int next, float[] matrix,
|
||||||
|
float div, double zoom, float scale) {
|
||||||
|
|
||||||
|
float z = 1 / div;
|
||||||
|
|
||||||
|
if (layer == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
glUseProgram(lineProgram);
|
||||||
|
|
||||||
|
glEnableVertexAttribArray(hLineVertexPosition);
|
||||||
|
glEnableVertexAttribArray(hLineTexturePosition);
|
||||||
|
|
||||||
|
glVertexAttribPointer(hLineVertexPosition, 4, GLES20.GL_SHORT,
|
||||||
|
false, 12, tile.lineOffset + LINE_VERTICES_DATA_POS_OFFSET);
|
||||||
|
|
||||||
|
glVertexAttribPointer(hLineTexturePosition, 2, GLES20.GL_SHORT,
|
||||||
|
false, 12, tile.lineOffset + LINE_VERTICES_DATA_TEX_OFFSET);
|
||||||
|
|
||||||
|
glUniformMatrix4fv(hLineMatrix, 1, false, matrix, 0);
|
||||||
|
|
||||||
|
// if (diff != 0)
|
||||||
|
// // diff < 0 means tile is parent
|
||||||
|
// z = (diff > 0) ? 1.0f / (1 << diff) : (1 << -diff);
|
||||||
|
|
||||||
|
// scale factor to map one pixel on tile to one pixel on screen:
|
||||||
|
// float pixel = 2.0f / (scale * z);
|
||||||
|
// GLES20.glUniform1f(hLineScale, pixel);
|
||||||
|
|
||||||
|
// line scale factor (for non fixed lines)
|
||||||
|
float s = FloatMath.sqrt(scale * z);
|
||||||
|
boolean blur = false;
|
||||||
|
GLES20.glUniform1f(hLineScale, 0);
|
||||||
|
|
||||||
|
LineLayer l = layer;
|
||||||
|
for (; l != null && l.layer < next; l = l.next) {
|
||||||
|
Line line = l.line;
|
||||||
|
if (line.fade != -1 && line.fade > zoom)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (line.fade >= zoom) {
|
||||||
|
float alpha = 1.0f;
|
||||||
|
|
||||||
|
alpha = (scale > 1.2f ? scale : 1.2f) - alpha;
|
||||||
|
if (alpha > 1.0f)
|
||||||
|
alpha = 1.0f;
|
||||||
|
glUniform4f(hLineColor,
|
||||||
|
line.color[0], line.color[1], line.color[2], alpha);
|
||||||
|
} else {
|
||||||
|
glUniform4fv(hLineColor, 1, line.color, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blur) {
|
||||||
|
GLES20.glUniform1f(hLineScale, 0);
|
||||||
|
blur = false;
|
||||||
|
}
|
||||||
|
if (l.isOutline) {
|
||||||
|
for (LineLayer o = l.outlines; o != null; o = o.outlines) {
|
||||||
|
if (line.blur != 0) {
|
||||||
|
GLES20.glUniform1f(hLineScale, (l.width + o.width) / (scale * z)
|
||||||
|
- (line.blur / (scale * z)));
|
||||||
|
blur = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zoom > MapGenerator.STROKE_MAX_ZOOM_LEVEL)
|
||||||
|
GLES20.glUniform1f(hLineWidth,
|
||||||
|
(l.width + o.width) / (scale * z));
|
||||||
|
else
|
||||||
|
GLES20.glUniform1f(hLineWidth, l.width / (scale * z)
|
||||||
|
+ o.width / s);
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLE_STRIP, o.offset, o.verticesCnt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (line.blur != 0) {
|
||||||
|
GLES20.glUniform1f(hLineScale, (l.width / s) * line.blur);
|
||||||
|
blur = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line.fixed || zoom > MapGenerator.STROKE_MAX_ZOOM_LEVEL) {
|
||||||
|
// invert scaling of extrusion vectors so that line width stays the same
|
||||||
|
GLES20.glUniform1f(hLineWidth, (l.width / (scale * z)));
|
||||||
|
} else {
|
||||||
|
GLES20.glUniform1f(hLineWidth, (l.width / s));
|
||||||
|
}
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLE_STRIP, l.offset, l.verticesCnt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glDisableVertexAttribArray(hLineVertexPosition);
|
||||||
|
glDisableVertexAttribArray(hLineTexturePosition);
|
||||||
|
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sizeOf(LineLayer layers) {
|
||||||
int size = 0;
|
int size = 0;
|
||||||
ShortBuffer sbuf = buf;
|
|
||||||
|
|
||||||
for (LineLayer l = layers; l != null; l = l.next)
|
for (LineLayer l = layers; l != null; l = l.next)
|
||||||
size += l.verticesCnt;
|
size += l.verticesCnt;
|
||||||
|
|
||||||
size *= NUM_VERTEX_FLOATS;
|
size *= NUM_VERTEX_SHORTS;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
if (buf == null || buf.capacity() < size) {
|
static void compileLayerData(LineLayer layers, ShortBuffer sbuf) {
|
||||||
ByteBuffer bbuf = ByteBuffer.allocateDirect(size * 2).order(
|
|
||||||
ByteOrder.nativeOrder());
|
|
||||||
sbuf = bbuf.asShortBuffer();
|
|
||||||
} else {
|
|
||||||
sbuf.clear();
|
|
||||||
}
|
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
|
|
||||||
// short[] data = new short[PoolItem.SIZE];
|
|
||||||
|
|
||||||
ShortItem last = null, items = null;
|
ShortItem last = null, items = null;
|
||||||
|
|
||||||
for (LineLayer l = layers; l != null; l = l.next) {
|
for (LineLayer l = layers; l != null; l = l.next) {
|
||||||
@ -151,8 +182,6 @@ class LineLayers {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (ShortItem item = l.pool; item != null; item = item.next) {
|
for (ShortItem item = l.pool; item != null; item = item.next) {
|
||||||
// PoolItem.toHalfFloat(item, data);
|
|
||||||
// sbuf.put(data, 0, item.used);
|
|
||||||
sbuf.put(item.vertices, 0, item.used);
|
sbuf.put(item.vertices, 0, item.used);
|
||||||
last = item;
|
last = item;
|
||||||
}
|
}
|
||||||
@ -166,19 +195,110 @@ class LineLayers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
l.pool = null;
|
l.pool = null;
|
||||||
|
l.curItem = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShortPool.add(items);
|
ShortPool.add(items);
|
||||||
|
|
||||||
sbuf.flip();
|
|
||||||
|
|
||||||
return sbuf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @SuppressLint("UseValueOf")
|
||||||
|
// private static final Boolean lock = new Boolean(true);
|
||||||
|
// private static final int POOL_LIMIT = 1500;
|
||||||
|
//
|
||||||
|
// static private LineLayer pool = null;
|
||||||
|
// static private int count = 0;
|
||||||
|
// static private int countAll = 0;
|
||||||
|
//
|
||||||
|
// static void finish() {
|
||||||
|
// synchronized (lock) {
|
||||||
|
// count = 0;
|
||||||
|
// countAll = 0;
|
||||||
|
// pool = null;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// static LineLayer get(int layer, Line line, float width, boolean outline) {
|
||||||
|
// synchronized (lock) {
|
||||||
|
//
|
||||||
|
// if (count == 0 && pool == null) {
|
||||||
|
// countAll++;
|
||||||
|
// return new LineLayer(layer, line, width, outline);
|
||||||
|
// }
|
||||||
|
// if (count > 0) {
|
||||||
|
// count--;
|
||||||
|
// } else {
|
||||||
|
// int c = 0;
|
||||||
|
// LineLayer tmp = pool;
|
||||||
|
//
|
||||||
|
// while (tmp != null) {
|
||||||
|
// c++;
|
||||||
|
// tmp = tmp.next;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Log.d("LineLayersl", "eek wrong count: " + c + " left");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// LineLayer it = pool;
|
||||||
|
// pool = pool.next;
|
||||||
|
// it.next = null;
|
||||||
|
// it.layer = layer;
|
||||||
|
// it.line = line;
|
||||||
|
// it.isOutline = outline;
|
||||||
|
// it.width = width;
|
||||||
|
// return it;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// static void add(LineLayer layers) {
|
||||||
|
// if (layers == null)
|
||||||
|
// return;
|
||||||
|
//
|
||||||
|
// synchronized (lock) {
|
||||||
|
//
|
||||||
|
// // limit pool items
|
||||||
|
// if (countAll < POOL_LIMIT) {
|
||||||
|
// LineLayer last = layers;
|
||||||
|
//
|
||||||
|
// while (true) {
|
||||||
|
// count++;
|
||||||
|
//
|
||||||
|
// if (last.next == null)
|
||||||
|
// break;
|
||||||
|
//
|
||||||
|
// last = last.next;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// last.next = pool;
|
||||||
|
// pool = layers;
|
||||||
|
//
|
||||||
|
// } else {
|
||||||
|
// int cleared = 0;
|
||||||
|
// LineLayer prev, tmp = layers;
|
||||||
|
// while (tmp != null) {
|
||||||
|
// prev = tmp;
|
||||||
|
// tmp = tmp.next;
|
||||||
|
//
|
||||||
|
// countAll--;
|
||||||
|
// cleared++;
|
||||||
|
//
|
||||||
|
// prev.next = null;
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
// Log.d("LineLayers", "sum: " + countAll + " free: " + count + " freed "
|
||||||
|
// + cleared);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
static void clear(LineLayer layer) {
|
static void clear(LineLayer layer) {
|
||||||
for (LineLayer l = layer; l != null; l = l.next) {
|
for (LineLayer l = layer; l != null; l = l.next) {
|
||||||
if (l.pool != null)
|
if (l.pool != null) {
|
||||||
ShortPool.add(l.pool);
|
ShortPool.add(l.pool);
|
||||||
|
l.pool = null;
|
||||||
|
l.curItem = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// LineLayers.add(layer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,8 +14,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapsforge.android.glrenderer;
|
package org.mapsforge.android.glrenderer;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import org.mapsforge.android.mapgenerator.IMapGenerator;
|
import org.mapsforge.android.mapgenerator.IMapGenerator;
|
||||||
import org.mapsforge.android.mapgenerator.MapGeneratorJob;
|
import org.mapsforge.android.mapgenerator.MapGeneratorJob;
|
||||||
import org.mapsforge.android.rendertheme.IRenderCallback;
|
import org.mapsforge.android.rendertheme.IRenderCallback;
|
||||||
@ -23,6 +21,7 @@ import org.mapsforge.android.rendertheme.RenderTheme;
|
|||||||
import org.mapsforge.android.rendertheme.renderinstruction.Area;
|
import org.mapsforge.android.rendertheme.renderinstruction.Area;
|
||||||
import org.mapsforge.android.rendertheme.renderinstruction.Caption;
|
import org.mapsforge.android.rendertheme.renderinstruction.Caption;
|
||||||
import org.mapsforge.android.rendertheme.renderinstruction.Line;
|
import org.mapsforge.android.rendertheme.renderinstruction.Line;
|
||||||
|
import org.mapsforge.android.rendertheme.renderinstruction.PathText;
|
||||||
import org.mapsforge.android.rendertheme.renderinstruction.RenderInstruction;
|
import org.mapsforge.android.rendertheme.renderinstruction.RenderInstruction;
|
||||||
import org.mapsforge.core.MercatorProjection;
|
import org.mapsforge.core.MercatorProjection;
|
||||||
import org.mapsforge.core.Tag;
|
import org.mapsforge.core.Tag;
|
||||||
@ -46,11 +45,11 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
|
|||||||
private static final double PI180 = (Math.PI / 180) / 1000000.0;
|
private static final double PI180 = (Math.PI / 180) / 1000000.0;
|
||||||
private static final double PIx4 = Math.PI * 4;
|
private static final double PIx4 = Math.PI * 4;
|
||||||
private static final double STROKE_INCREASE = Math.sqrt(2);
|
private static final double STROKE_INCREASE = Math.sqrt(2);
|
||||||
private static final byte STROKE_MIN_ZOOM_LEVEL = 12;
|
|
||||||
private static final byte LAYERS = 11;
|
private static final byte LAYERS = 11;
|
||||||
private static final double f900913 = 20037508.342789244;
|
private static final double f900913 = 20037508.342789244;
|
||||||
// 134217728
|
|
||||||
// 2147483648.000
|
static final byte STROKE_MIN_ZOOM_LEVEL = 12;
|
||||||
|
static final byte STROKE_MAX_ZOOM_LEVEL = 17;
|
||||||
|
|
||||||
private static RenderTheme renderTheme;
|
private static RenderTheme renderTheme;
|
||||||
|
|
||||||
@ -66,14 +65,23 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
|
|||||||
private LineLayer mCurLineLayer;
|
private LineLayer mCurLineLayer;
|
||||||
private PolygonLayer mCurPolyLayer;
|
private PolygonLayer mCurPolyLayer;
|
||||||
|
|
||||||
private ArrayList<TextItem> mLabels;
|
private TextItem mLabels;
|
||||||
|
|
||||||
private int mDrawingLayer;
|
private int mDrawingLayer;
|
||||||
private int mLevels;
|
private int mLevels;
|
||||||
|
|
||||||
private boolean useSphericalMercator = false;
|
|
||||||
private float mStrokeScale = 1.0f;
|
private float mStrokeScale = 1.0f;
|
||||||
|
|
||||||
|
private boolean mProjected;
|
||||||
|
// private boolean mProjectedResult;
|
||||||
|
private float mSimplify;
|
||||||
|
// private boolean firstMatch;
|
||||||
|
// private boolean prevClosed;
|
||||||
|
|
||||||
|
private RenderInstruction[] mRenderInstructions = null;
|
||||||
|
|
||||||
|
private final String TAG_WATER = "water".intern();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@ -84,53 +92,62 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
|
|||||||
private float mPoiX = 256;
|
private float mPoiX = 256;
|
||||||
private float mPoiY = 256;
|
private float mPoiY = 256;
|
||||||
|
|
||||||
private Tag mTagEmptyName = new Tag("name", "");
|
private Tag mTagEmptyName = new Tag(Tag.TAG_KEY_NAME, null, false);
|
||||||
private Tag mTagName;
|
private Tag mTagName;
|
||||||
|
|
||||||
private void filterTags(Tag[] tags) {
|
private void filterTags(Tag[] tags) {
|
||||||
for (int i = 0; i < tags.length; i++) {
|
for (int i = 0; i < tags.length; i++) {
|
||||||
// Log.d(TAG, "check tag: " + tags[i]);
|
// Log.d(TAG, "check tag: " + tags[i]);
|
||||||
if (tags[i].key == mTagEmptyName.key && tags[i].value != null) {
|
if (tags[i].key == Tag.TAG_KEY_NAME && tags[i].value != null) {
|
||||||
mTagName = tags[i];
|
mTagName = tags[i];
|
||||||
tags[i] = mTagEmptyName;
|
tags[i] = mTagEmptyName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// private RenderInstruction[] mNodeRenderInstructions;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void renderPointOfInterest(byte layer, float latitude, float longitude,
|
public void renderPointOfInterest(byte layer, float latitude, float longitude,
|
||||||
Tag[] tags) {
|
Tag[] tags) {
|
||||||
|
|
||||||
mTagName = null;
|
mTagName = null;
|
||||||
|
|
||||||
long x = mCurrentTile.x;
|
if (mMapProjection != null)
|
||||||
long y = mCurrentTile.y;
|
{
|
||||||
long z = Tile.TILE_SIZE << mCurrentTile.zoomLevel;
|
long x = mCurrentTile.x;
|
||||||
|
long y = mCurrentTile.y;
|
||||||
|
long z = Tile.TILE_SIZE << mCurrentTile.zoomLevel;
|
||||||
|
|
||||||
double divx, divy;
|
double divx, divy;
|
||||||
long dx = (x - (z >> 1));
|
long dx = (x - (z >> 1));
|
||||||
long dy = (y - (z >> 1));
|
long dy = (y - (z >> 1));
|
||||||
|
|
||||||
if (useSphericalMercator) {
|
if (mMapProjection == WebMercator.NAME) {
|
||||||
divx = f900913 / (z >> 1);
|
double div = f900913 / (z >> 1);
|
||||||
divy = f900913 / (z >> 1);
|
// divy = f900913 / (z >> 1);
|
||||||
mPoiX = (float) (longitude / divx - dx);
|
mPoiX = (float) (longitude / div - dx);
|
||||||
mPoiY = (float) (latitude / divy + dy);
|
mPoiY = (float) (latitude / div + dy);
|
||||||
|
} else {
|
||||||
|
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 {
|
} else {
|
||||||
divx = 180000000.0 / (z >> 1);
|
mPoiX = longitude;
|
||||||
divy = z / PIx4;
|
mPoiY = latitude;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove tags that should not be cached in Rendertheme
|
// remove tags that should not be cached in Rendertheme
|
||||||
filterTags(tags);
|
filterTags(tags);
|
||||||
// Log.d(TAG, "renderPointOfInterest: " + mTagName);
|
// Log.d(TAG, "renderPointOfInterest: " + mTagName);
|
||||||
|
|
||||||
|
// mNodeRenderInstructions =
|
||||||
MapGenerator.renderTheme.matchNode(this, tags, mCurrentTile.zoomLevel);
|
MapGenerator.renderTheme.matchNode(this, tags, mCurrentTile.zoomLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,82 +157,6 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean mProjected;
|
|
||||||
private boolean mProjectedResult;
|
|
||||||
private float mSimplify;
|
|
||||||
|
|
||||||
private boolean projectToTile() {
|
|
||||||
if (mProjected)
|
|
||||||
return mProjectedResult;
|
|
||||||
|
|
||||||
float[] coords = mWayNodes;
|
|
||||||
|
|
||||||
long x = mCurrentTile.x;
|
|
||||||
long y = mCurrentTile.y;
|
|
||||||
long z = Tile.TILE_SIZE << mCurrentTile.zoomLevel;
|
|
||||||
float min = mSimplify;
|
|
||||||
|
|
||||||
double divx, divy;
|
|
||||||
long dx = (x - (z >> 1));
|
|
||||||
long dy = (y - (z >> 1));
|
|
||||||
|
|
||||||
if (useSphericalMercator) {
|
|
||||||
divx = f900913 / (z >> 1);
|
|
||||||
divy = f900913 / (z >> 1);
|
|
||||||
} else {
|
|
||||||
divx = 180000000.0 / (z >> 1);
|
|
||||||
divy = z / PIx4;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int pos = 0, outPos = 0, i = 0, m = mWays.length; i < m; i++) {
|
|
||||||
int len = mWays[i];
|
|
||||||
if (len == 0)
|
|
||||||
continue;
|
|
||||||
int cnt = 0;
|
|
||||||
float lat, lon, prevLon = 0, prevLat = 0;
|
|
||||||
|
|
||||||
for (int end = pos + len; pos < end; pos += 2) {
|
|
||||||
|
|
||||||
if (useSphericalMercator) {
|
|
||||||
lon = (float) (coords[pos] / divx - dx);
|
|
||||||
lat = (float) (coords[pos + 1] / divy + dy);
|
|
||||||
} else {
|
|
||||||
lon = (float) ((coords[pos]) / divx - dx);
|
|
||||||
double sinLat = Math.sin(coords[pos + 1] * PI180);
|
|
||||||
lat = (float) (Math.log((1.0 + sinLat) / (1.0 - sinLat)) * divy + dy);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cnt != 0) {
|
|
||||||
// drop small distance intermediate nodes
|
|
||||||
|
|
||||||
if (lat == prevLat && lon == prevLon)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if ((pos != end - 2) &&
|
|
||||||
!((lat > prevLat + min || lat < prevLat - min) ||
|
|
||||||
(lon > prevLon + min || lon < prevLon - min)))
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
coords[outPos++] = prevLon = lon;
|
|
||||||
coords[outPos++] = prevLat = lat;
|
|
||||||
|
|
||||||
cnt += 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
mWays[i] = (short) cnt;
|
|
||||||
}
|
|
||||||
mProjected = true;
|
|
||||||
mProjectedResult = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// private boolean firstMatch;
|
|
||||||
// private boolean prevClosed;
|
|
||||||
|
|
||||||
private RenderInstruction[] mRenderInstructions = null;
|
|
||||||
|
|
||||||
private final String TAG_WATER = "water".intern();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void renderWay(byte layer, Tag[] tags, float[] wayNodes, short[] wayLength,
|
public void renderWay(byte layer, Tag[] tags, float[] wayNodes, short[] wayLength,
|
||||||
boolean closed) {
|
boolean closed) {
|
||||||
@ -239,6 +180,9 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
|
|||||||
mWayNodes = wayNodes;
|
mWayNodes = wayNodes;
|
||||||
mWays = wayLength;
|
mWays = wayLength;
|
||||||
|
|
||||||
|
// remove tags that should not be cached in Rendertheme
|
||||||
|
filterTags(tags);
|
||||||
|
|
||||||
// if (mRenderInstructions != null) {
|
// if (mRenderInstructions != null) {
|
||||||
// for (int i = 0, n = mRenderInstructions.length; i < n; i++)
|
// for (int i = 0, n = mRenderInstructions.length; i < n; i++)
|
||||||
// mRenderInstructions[i].renderWay(this, tags);
|
// mRenderInstructions[i].renderWay(this, tags);
|
||||||
@ -266,7 +210,6 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
|
|||||||
mRenderInstructions = MapGenerator.renderTheme.matchWay(this, debugTagWay,
|
mRenderInstructions = MapGenerator.renderTheme.matchWay(this, debugTagWay,
|
||||||
(byte) 0, true, true);
|
(byte) 0, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -277,9 +220,10 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (caption.textKey == mTagEmptyName.key) {
|
if (caption.textKey == mTagEmptyName.key) {
|
||||||
if (mLabels == null)
|
|
||||||
mLabels = new ArrayList<TextItem>();
|
TextItem t = new TextItem(mWayNodes[0], mWayNodes[1], mTagName.value, caption);
|
||||||
mLabels.add(new TextItem(mWayNodes[0], mWayNodes[1], mTagName.value, caption));
|
t.next = mLabels;
|
||||||
|
mLabels = t;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,9 +236,23 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (caption.textKey == mTagEmptyName.key) {
|
if (caption.textKey == mTagEmptyName.key) {
|
||||||
if (mLabels == null)
|
TextItem t = new TextItem(mPoiX, mPoiY, mTagName.value, caption);
|
||||||
mLabels = new ArrayList<TextItem>();
|
t.next = mLabels;
|
||||||
mLabels.add(new TextItem(mPoiX, mPoiY, mTagName.value, caption));
|
mLabels = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderWayText(PathText pathText) {
|
||||||
|
// Log.d(TAG, "renderWayText: " + mTagName);
|
||||||
|
|
||||||
|
if (mTagName == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (pathText.textKey == mTagEmptyName.key) {
|
||||||
|
|
||||||
|
mLabels = WayDecorator.renderText(mWayNodes, mTagName.value, pathText, 0,
|
||||||
|
mWays[0], mLabels);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,13 +278,23 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
|
|||||||
private int countNodes;
|
private int countNodes;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void renderWay(Line line) {
|
public void renderWay(Line line, int level) {
|
||||||
|
|
||||||
projectToTile();
|
projectToTile();
|
||||||
|
|
||||||
LineLayer outlineLayer = null;
|
if (line.outline && mCurLineLayer == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
float w = line.width;
|
||||||
|
|
||||||
|
if (!line.fixed) {
|
||||||
|
w *= mStrokeScale;
|
||||||
|
w *= mProjectionScaleFactor;
|
||||||
|
}
|
||||||
|
|
||||||
LineLayer lineLayer = null;
|
LineLayer lineLayer = null;
|
||||||
|
|
||||||
int numLayer = mDrawingLayer + line.level;
|
int numLayer = mDrawingLayer + level;
|
||||||
|
|
||||||
LineLayer l = mLineLayers;
|
LineLayer l = mLineLayers;
|
||||||
|
|
||||||
@ -334,7 +302,9 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
|
|||||||
lineLayer = mCurLineLayer;
|
lineLayer = mCurLineLayer;
|
||||||
} else if (l == null || l.layer > numLayer) {
|
} else if (l == null || l.layer > numLayer) {
|
||||||
// insert new layer at start
|
// insert new layer at start
|
||||||
lineLayer = new LineLayer(numLayer, line, false);
|
lineLayer = new LineLayer(numLayer, line, w, line.outline);
|
||||||
|
// lineLayer = LineLayers.get(numLayer, line, w, false);
|
||||||
|
|
||||||
lineLayer.next = l;
|
lineLayer.next = l;
|
||||||
mLineLayers = lineLayer;
|
mLineLayers = lineLayer;
|
||||||
} else {
|
} else {
|
||||||
@ -346,7 +316,8 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
|
|||||||
}
|
}
|
||||||
// insert new layer between current and next layer
|
// insert new layer between current and next layer
|
||||||
if (l.next == null || l.next.layer > numLayer) {
|
if (l.next == null || l.next.layer > numLayer) {
|
||||||
lineLayer = new LineLayer(numLayer, line, false);
|
lineLayer = new LineLayer(numLayer, line, w, line.outline);
|
||||||
|
// lineLayer = LineLayers.get(numLayer, line, w, false);
|
||||||
lineLayer.next = l.next;
|
lineLayer.next = l.next;
|
||||||
l.next = lineLayer;
|
l.next = lineLayer;
|
||||||
}
|
}
|
||||||
@ -357,77 +328,83 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
|
|||||||
if (lineLayer == null)
|
if (lineLayer == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (line.outline) {
|
||||||
|
lineLayer.addOutline(mCurLineLayer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
mCurLineLayer = lineLayer;
|
mCurLineLayer = lineLayer;
|
||||||
|
|
||||||
float w = line.strokeWidth;
|
boolean round = line.round;
|
||||||
|
|
||||||
if (!line.fixed) {
|
|
||||||
w *= mStrokeScale;
|
|
||||||
w *= mProjectionScaleFactor;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
w *= 1.2; // TODO make this dependent on dpi
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0, pos = 0, n = mWays.length; i < n; i++) {
|
for (int i = 0, pos = 0, n = mWays.length; i < n; i++) {
|
||||||
int length = mWays[i];
|
int length = mWays[i];
|
||||||
|
if (length < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// save some vertices
|
||||||
|
if (round && i > 200) {
|
||||||
|
// Log.d(TAG, "WAY TOO MANY LINES!!!");
|
||||||
|
round = false;
|
||||||
|
}
|
||||||
// need at least two points
|
// need at least two points
|
||||||
if (length >= 4) {
|
if (length >= 4) {
|
||||||
lineLayer.addLine(mWayNodes, pos, length, w, line.round);
|
lineLayer.addLine(mWayNodes, pos, length);
|
||||||
countLines++;
|
countLines++;
|
||||||
countNodes += length;
|
countNodes += length;
|
||||||
}
|
}
|
||||||
pos += length;
|
pos += length;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (line.outline < 0)
|
// if (line.outline < 0)
|
||||||
return;
|
// return;
|
||||||
|
//
|
||||||
Line outline = MapGenerator.renderTheme.getOutline(line.outline);
|
// Line outline = MapGenerator.renderTheme.getOutline(line.outline);
|
||||||
|
//
|
||||||
if (outline == null)
|
// if (outline == null)
|
||||||
return;
|
// return;
|
||||||
|
//
|
||||||
numLayer = mDrawingLayer + outline.level;
|
// numLayer = mDrawingLayer + outline.getLevel();
|
||||||
|
//
|
||||||
l = mLineLayers;
|
// l = mLineLayers;
|
||||||
|
//
|
||||||
if (l == null || l.layer > numLayer) {
|
// if (l == null || l.layer > numLayer) {
|
||||||
// insert new layer at start
|
// // insert new layer at start
|
||||||
outlineLayer = new LineLayer(numLayer, outline, true);
|
// outlineLayer = new LineLayer(numLayer, outline, w, true);
|
||||||
outlineLayer.next = l;
|
// // outlineLayer = LineLayers.get(numLayer, outline, w, true);
|
||||||
mLineLayers = outlineLayer;
|
// outlineLayer.next = l;
|
||||||
} else {
|
// mLineLayers = outlineLayer;
|
||||||
while (l != null) {
|
// } else {
|
||||||
if (l.layer == numLayer) {
|
// while (l != null) {
|
||||||
outlineLayer = l;
|
// if (l.layer == numLayer) {
|
||||||
break;
|
// outlineLayer = l;
|
||||||
}
|
// break;
|
||||||
// insert new layer between current and next layer
|
// }
|
||||||
if (l.next == null || l.next.layer > numLayer) {
|
// // insert new layer between current and next layer
|
||||||
outlineLayer = new LineLayer(numLayer, outline, true);
|
// if (l.next == null || l.next.layer > numLayer) {
|
||||||
outlineLayer.next = l.next;
|
// outlineLayer = new LineLayer(numLayer, outline, w, true);
|
||||||
l.next = outlineLayer;
|
// // outlineLayer = LineLayers.get(numLayer, outline, w, true);
|
||||||
}
|
// outlineLayer.next = l.next;
|
||||||
l = l.next;
|
// l.next = outlineLayer;
|
||||||
}
|
// }
|
||||||
}
|
// l = l.next;
|
||||||
|
// }
|
||||||
if (outlineLayer != null)
|
// }
|
||||||
outlineLayer.addOutline(lineLayer);
|
//
|
||||||
|
// if (outlineLayer != null)
|
||||||
|
// outlineLayer.addOutline(lineLayer);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void renderArea(Area area) {
|
public void renderArea(Area area, int level) {
|
||||||
if (!mDebugDrawPolygons)
|
if (!mDebugDrawPolygons)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!projectToTile())
|
if (!mProjected && !projectToTile())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int numLayer = mDrawingLayer + area.level;
|
int numLayer = mDrawingLayer + level;
|
||||||
|
|
||||||
PolygonLayer layer = null;
|
PolygonLayer layer = null;
|
||||||
PolygonLayer l = mPolyLayers;
|
PolygonLayer l = mPolyLayers;
|
||||||
@ -463,6 +440,9 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
|
|||||||
|
|
||||||
for (int i = 0, pos = 0, n = mWays.length; i < n; i++) {
|
for (int i = 0, pos = 0, n = mWays.length; i < n; i++) {
|
||||||
int length = mWays[i];
|
int length = mWays[i];
|
||||||
|
if (length < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
// need at least three points
|
// need at least three points
|
||||||
if (length >= 6)
|
if (length >= 6)
|
||||||
layer.addPolygon(mWayNodes, pos, length);
|
layer.addPolygon(mWayNodes, pos, length);
|
||||||
@ -470,6 +450,7 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
|
|||||||
pos += length;
|
pos += length;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if (area.line != null)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -478,12 +459,6 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void renderWayText(String text, Paint paint, Paint stroke) {
|
|
||||||
// TODO Auto-generated method stub
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void cleanup() {
|
public void cleanup() {
|
||||||
// TODO Auto-generated method stub
|
// TODO Auto-generated method stub
|
||||||
@ -495,23 +470,27 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean executeJob(MapGeneratorJob mapGeneratorJob) {
|
public boolean executeJob(MapGeneratorJob mapGeneratorJob) {
|
||||||
|
GLMapTile tile;
|
||||||
|
|
||||||
if (mMapDatabase == null)
|
if (mMapDatabase == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
useSphericalMercator = WebMercator.NAME.equals(mMapDatabase.getMapProjection());
|
tile = mCurrentTile = (GLMapTile) mapGeneratorJob.tile;
|
||||||
|
|
||||||
mCurrentTile = (GLMapTile) mapGeneratorJob.tile;
|
|
||||||
mDebugDrawPolygons = !mapGeneratorJob.debugSettings.mDisablePolygons;
|
mDebugDrawPolygons = !mapGeneratorJob.debugSettings.mDisablePolygons;
|
||||||
mDebugDrawUnmatched = mapGeneratorJob.debugSettings.mDrawUnmatchted;
|
mDebugDrawUnmatched = mapGeneratorJob.debugSettings.mDrawUnmatchted;
|
||||||
if (mCurrentTile.isLoading || mCurrentTile.isReady)
|
|
||||||
|
if (tile.isLoading || tile.isReady || tile.isCanceled)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
mCurrentTile.isLoading = true;
|
tile.isLoading = true;
|
||||||
|
|
||||||
mLevels = MapGenerator.renderTheme.getLevels();
|
mLevels = MapGenerator.renderTheme.getLevels();
|
||||||
|
|
||||||
setScaleStrokeWidth(mCurrentTile.zoomLevel);
|
// limit stroke scale at z=17
|
||||||
|
if (tile.zoomLevel < STROKE_MAX_ZOOM_LEVEL)
|
||||||
|
setScaleStrokeWidth(tile.zoomLevel);
|
||||||
|
else
|
||||||
|
setScaleStrokeWidth(STROKE_MAX_ZOOM_LEVEL);
|
||||||
|
|
||||||
mLineLayers = null;
|
mLineLayers = null;
|
||||||
mPolyLayers = null;
|
mPolyLayers = null;
|
||||||
@ -520,43 +499,54 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
|
|||||||
// firstMatch = true;
|
// firstMatch = true;
|
||||||
countLines = 0;
|
countLines = 0;
|
||||||
countNodes = 0;
|
countNodes = 0;
|
||||||
mProjectionScaleFactor = (float) (1.0 / Math.cos(MercatorProjection
|
|
||||||
.pixelYToLatitude(mCurrentTile.pixelY, mCurrentTile.zoomLevel)
|
|
||||||
* (Math.PI / 180))); // / 1.5f;
|
|
||||||
|
|
||||||
if (mMapDatabase.executeQuery(mCurrentTile, this) != QueryResult.SUCCESS) {
|
// acount for area changes with latitude
|
||||||
|
mProjectionScaleFactor = 0.5f + (float) (0.5 / Math.cos(MercatorProjection
|
||||||
|
.pixelYToLatitude(tile.pixelY, tile.zoomLevel)
|
||||||
|
* (Math.PI / 180)));
|
||||||
|
|
||||||
|
if (mMapDatabase.executeQuery(tile, this) != QueryResult.SUCCESS) {
|
||||||
|
Log.d(TAG, "Failed loading: " + tile);
|
||||||
LineLayers.clear(mLineLayers);
|
LineLayers.clear(mLineLayers);
|
||||||
PolygonLayers.clear(mPolyLayers);
|
PolygonLayers.clear(mPolyLayers);
|
||||||
mLineLayers = null;
|
mLineLayers = null;
|
||||||
mPolyLayers = null;
|
mPolyLayers = null;
|
||||||
mCurrentTile.isLoading = false;
|
tile.isLoading = false;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mapGeneratorJob.debugSettings.mDrawTileFrames) {
|
if (mapGeneratorJob.debugSettings.mDrawTileFrames) {
|
||||||
|
|
||||||
|
final float[] debugBoxCoords = { 0, 0, 0, Tile.TILE_SIZE,
|
||||||
|
Tile.TILE_SIZE, Tile.TILE_SIZE, Tile.TILE_SIZE, 0, 0, 0 };
|
||||||
|
final short[] debugBoxIndex = { 10 };
|
||||||
|
|
||||||
mTagName = new Tag("name", countLines + " " + countNodes + " "
|
mTagName = new Tag("name", countLines + " " + countNodes + " "
|
||||||
+ mCurrentTile.toString(), false);
|
+ tile.toString(), false);
|
||||||
mPoiX = 10;
|
mPoiX = Tile.TILE_SIZE >> 1;
|
||||||
mPoiY = 10;
|
mPoiY = 10;
|
||||||
MapGenerator.renderTheme.matchNode(this, debugTagWay, (byte) 0);
|
MapGenerator.renderTheme.matchNode(this, debugTagWay, (byte) 0);
|
||||||
// float[] coords = { 0, 0, 0, Tile.TILE_SIZE, Tile.TILE_SIZE, Tile.TILE_SIZE,
|
|
||||||
// Tile.TILE_SIZE, 0, 0, 0 };
|
mWays = debugBoxIndex;
|
||||||
// LineLayer ll = mLineLayers.getLayer(Integer.MAX_VALUE, Color.BLACK, false,
|
mWayNodes = debugBoxCoords;
|
||||||
// true, -1);
|
mDrawingLayer = 10 * mLevels;
|
||||||
// ll.addLine(coords, 0, coords.length, 1.5f, false);
|
MapGenerator.renderTheme.matchWay(this, debugTagBox, (byte) 0, false, true);
|
||||||
}
|
}
|
||||||
mCurrentTile.lineLayers = mLineLayers;
|
tile.lineLayers = mLineLayers;
|
||||||
mCurrentTile.polygonLayers = mPolyLayers;
|
tile.polygonLayers = mPolyLayers;
|
||||||
mCurrentTile.labels = mLabels;
|
tile.labels = mLabels;
|
||||||
mCurPolyLayer = null;
|
mCurPolyLayer = null;
|
||||||
mCurLineLayer = null;
|
mCurLineLayer = null;
|
||||||
|
|
||||||
mCurrentTile.newData = true;
|
tile.newData = true;
|
||||||
|
tile.isLoading = false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Tag[] debugTagWay = { new Tag("debug", "way") };
|
private final Tag[] debugTagBox = { new Tag("debug", "box") };
|
||||||
private Tag[] debugTagArea = { new Tag("debug", "area") };
|
private final Tag[] debugTagWay = { new Tag("debug", "way") };
|
||||||
|
private final Tag[] debugTagArea = { new Tag("debug", "area") };
|
||||||
|
|
||||||
private float mProjectionScaleFactor;
|
private float mProjectionScaleFactor;
|
||||||
|
|
||||||
@ -586,9 +576,12 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
|
|||||||
mStrokeScale = 1;
|
mStrokeScale = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String mMapProjection;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setMapDatabase(IMapDatabase mapDatabase) {
|
public void setMapDatabase(IMapDatabase mapDatabase) {
|
||||||
mMapDatabase = mapDatabase;
|
mMapDatabase = mapDatabase;
|
||||||
|
mMapProjection = mMapDatabase.getMapProjection();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -609,4 +602,76 @@ public class MapGenerator implements IMapGenerator, IRenderCallback, IMapDatabas
|
|||||||
|
|
||||||
return mRenderInstructions != null;
|
return mRenderInstructions != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean projectToTile() {
|
||||||
|
if (mProjected || mMapProjection == null)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
boolean useWebMercator = false;
|
||||||
|
|
||||||
|
if (mMapProjection == WebMercator.NAME)
|
||||||
|
useWebMercator = true;
|
||||||
|
|
||||||
|
float[] coords = mWayNodes;
|
||||||
|
|
||||||
|
long x = mCurrentTile.x;
|
||||||
|
long y = mCurrentTile.y;
|
||||||
|
long z = Tile.TILE_SIZE << mCurrentTile.zoomLevel;
|
||||||
|
float min = mSimplify;
|
||||||
|
|
||||||
|
double divx, divy;
|
||||||
|
long dx = (x - (z >> 1));
|
||||||
|
long dy = (y - (z >> 1));
|
||||||
|
|
||||||
|
if (useWebMercator) {
|
||||||
|
divx = f900913 / (z >> 1);
|
||||||
|
divy = f900913 / (z >> 1);
|
||||||
|
} else {
|
||||||
|
divx = 180000000.0 / (z >> 1);
|
||||||
|
divy = z / PIx4;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int pos = 0, outPos = 0, i = 0, m = mWays.length; i < m; i++) {
|
||||||
|
int len = mWays[i];
|
||||||
|
if (len == 0)
|
||||||
|
continue;
|
||||||
|
if (len < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
int cnt = 0;
|
||||||
|
float lat, lon, prevLon = 0, prevLat = 0;
|
||||||
|
|
||||||
|
for (int end = pos + len; pos < end; pos += 2) {
|
||||||
|
|
||||||
|
if (useWebMercator) {
|
||||||
|
lon = (float) (coords[pos] / divx - dx);
|
||||||
|
lat = (float) (coords[pos + 1] / divy + dy);
|
||||||
|
} else {
|
||||||
|
lon = (float) ((coords[pos]) / divx - dx);
|
||||||
|
double sinLat = Math.sin(coords[pos + 1] * PI180);
|
||||||
|
lat = (float) (Math.log((1.0 + sinLat) / (1.0 - sinLat)) * divy + dy);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cnt != 0) {
|
||||||
|
// drop small distance intermediate nodes
|
||||||
|
if (lat == prevLat && lon == prevLon)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((pos != end - 2) &&
|
||||||
|
!((lat > prevLat + min || lat < prevLat - min) ||
|
||||||
|
(lon > prevLon + min || lon < prevLon - min)))
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
coords[outPos++] = prevLon = lon;
|
||||||
|
coords[outPos++] = prevLat = lat;
|
||||||
|
|
||||||
|
cnt += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
mWays[i] = (short) cnt;
|
||||||
|
}
|
||||||
|
mProjected = true;
|
||||||
|
// mProjectedResult = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -15,11 +15,14 @@
|
|||||||
package org.mapsforge.android.glrenderer;
|
package org.mapsforge.android.glrenderer;
|
||||||
|
|
||||||
import org.mapsforge.android.rendertheme.renderinstruction.Area;
|
import org.mapsforge.android.rendertheme.renderinstruction.Area;
|
||||||
|
import org.mapsforge.core.Tile;
|
||||||
|
|
||||||
class PolygonLayer {
|
class PolygonLayer {
|
||||||
|
private static final float S = MapRenderer.COORD_MULTIPLIER;
|
||||||
|
|
||||||
PolygonLayer next;
|
PolygonLayer next;
|
||||||
Area area;
|
Area area;
|
||||||
private static final float SCALE_FACTOR = 16.0f;
|
// private static final float MapRenderer.COORD_MULTIPLIER = 8.0f;
|
||||||
private boolean first = true;
|
private boolean first = true;
|
||||||
private float originX;
|
private float originX;
|
||||||
private float originY;
|
private float originY;
|
||||||
@ -53,8 +56,8 @@ class PolygonLayer {
|
|||||||
|
|
||||||
if (first) {
|
if (first) {
|
||||||
first = false;
|
first = false;
|
||||||
originX = points[pos];
|
originX = Tile.TILE_SIZE >> 1; // points[pos];
|
||||||
originY = points[pos + 1];
|
originY = Tile.TILE_SIZE >> 1; // points[pos + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
short[] curVertices = curItem.vertices;
|
short[] curVertices = curItem.vertices;
|
||||||
@ -65,24 +68,25 @@ class PolygonLayer {
|
|||||||
outPos = 0;
|
outPos = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
curVertices[outPos++] = (short) (originX * SCALE_FACTOR);
|
curVertices[outPos++] = (short) (originX * S);
|
||||||
curVertices[outPos++] = (short) (originY * SCALE_FACTOR);
|
curVertices[outPos++] = (short) (originY * S);
|
||||||
|
|
||||||
|
int MAX = ShortItem.SIZE;
|
||||||
int remaining = length;
|
int remaining = length;
|
||||||
int inPos = pos;
|
int inPos = pos;
|
||||||
while (remaining > 0) {
|
while (remaining > 0) {
|
||||||
|
|
||||||
if (outPos == ShortItem.SIZE) {
|
if (outPos == MAX) {
|
||||||
curVertices = getNextItem();
|
curVertices = getNextItem();
|
||||||
outPos = 0;
|
outPos = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int len = remaining;
|
int len = remaining;
|
||||||
if (len > (ShortItem.SIZE) - outPos)
|
if (len > MAX - outPos)
|
||||||
len = (ShortItem.SIZE) - outPos;
|
len = MAX - outPos;
|
||||||
|
|
||||||
for (int i = 0; i < len; i++)
|
for (int i = 0; i < len; i++)
|
||||||
curVertices[outPos++] = (short) (points[inPos++] * SCALE_FACTOR);
|
curVertices[outPos++] = (short) (points[inPos++] * S);
|
||||||
|
|
||||||
// System.arraycopy(points, inPos, curVertices, outPos, len);
|
// System.arraycopy(points, inPos, curVertices, outPos, len);
|
||||||
|
|
||||||
@ -92,13 +96,13 @@ class PolygonLayer {
|
|||||||
remaining -= len;
|
remaining -= len;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (outPos == PoolItem.SIZE) {
|
if (outPos == MAX) {
|
||||||
curVertices = getNextItem();
|
curVertices = getNextItem();
|
||||||
outPos = 0;
|
outPos = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
curVertices[outPos++] = (short) (points[pos + 0] * SCALE_FACTOR);
|
curVertices[outPos++] = (short) (points[pos + 0] * S);
|
||||||
curVertices[outPos++] = (short) (points[pos + 1] * SCALE_FACTOR);
|
curVertices[outPos++] = (short) (points[pos + 1] * S);
|
||||||
|
|
||||||
curItem.used = outPos;
|
curItem.used = outPos;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,172 +14,269 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapsforge.android.glrenderer;
|
package org.mapsforge.android.glrenderer;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import static android.opengl.GLES20.GL_BLEND;
|
||||||
import java.nio.ByteOrder;
|
import static android.opengl.GLES20.GL_EQUAL;
|
||||||
|
import static android.opengl.GLES20.GL_INVERT;
|
||||||
|
import static android.opengl.GLES20.GL_KEEP;
|
||||||
|
import static android.opengl.GLES20.GL_NEVER;
|
||||||
|
import static android.opengl.GLES20.GL_STENCIL_TEST;
|
||||||
|
import static android.opengl.GLES20.GL_TRIANGLE_FAN;
|
||||||
|
import static android.opengl.GLES20.GL_TRIANGLE_STRIP;
|
||||||
|
import static android.opengl.GLES20.GL_ZERO;
|
||||||
|
import static android.opengl.GLES20.glColorMask;
|
||||||
|
import static android.opengl.GLES20.glDisable;
|
||||||
|
import static android.opengl.GLES20.glDrawArrays;
|
||||||
|
import static android.opengl.GLES20.glEnable;
|
||||||
|
import static android.opengl.GLES20.glEnableVertexAttribArray;
|
||||||
|
import static android.opengl.GLES20.glGetAttribLocation;
|
||||||
|
import static android.opengl.GLES20.glGetUniformLocation;
|
||||||
|
import static android.opengl.GLES20.glStencilFunc;
|
||||||
|
import static android.opengl.GLES20.glStencilMask;
|
||||||
|
import static android.opengl.GLES20.glStencilOp;
|
||||||
|
import static android.opengl.GLES20.glUniform4f;
|
||||||
|
import static android.opengl.GLES20.glUniform4fv;
|
||||||
|
import static android.opengl.GLES20.glUniformMatrix4fv;
|
||||||
|
import static android.opengl.GLES20.glUseProgram;
|
||||||
|
import static android.opengl.GLES20.glVertexAttribPointer;
|
||||||
|
|
||||||
import java.nio.ShortBuffer;
|
import java.nio.ShortBuffer;
|
||||||
|
|
||||||
import org.mapsforge.core.Tile;
|
import org.mapsforge.android.utils.GlUtils;
|
||||||
|
|
||||||
|
import android.opengl.GLES20;
|
||||||
|
|
||||||
class PolygonLayers {
|
class PolygonLayers {
|
||||||
private static final int NUM_VERTEX_FLOATS = 2;
|
private static final int NUM_VERTEX_SHORTS = 2;
|
||||||
// static final float[] mFillCoords = { -2, Tile.TILE_SIZE + 1,
|
private static final int POLYGON_VERTICES_DATA_POS_OFFSET = 0;
|
||||||
// Tile.TILE_SIZE + 1, Tile.TILE_SIZE + 1, -2,
|
private static int STENCIL_BITS = 8;
|
||||||
// -2, Tile.TILE_SIZE + 1, -2 };
|
|
||||||
|
|
||||||
// private static short[] mByteFillCoords = null;
|
private static PolygonLayer[] mFillPolys;
|
||||||
|
|
||||||
// static FloatBuffer compileLayerData(PolygonLayer layers, FloatBuffer buf) {
|
private static int polygonProgram;
|
||||||
// FloatBuffer fbuf = buf;
|
private static int hPolygonVertexPosition;
|
||||||
// int size = 4;
|
private static int hPolygonMatrix;
|
||||||
//
|
private static int hPolygonColor;
|
||||||
// for (PolygonLayer l = layers; l != null; l = l.next)
|
|
||||||
// size += l.verticesCnt;
|
|
||||||
//
|
|
||||||
// size *= NUM_VERTEX_FLOATS;
|
|
||||||
//
|
|
||||||
// if (buf == null || buf.capacity() < size) {
|
|
||||||
// ByteBuffer bbuf = ByteBuffer.allocateDirect(size * 4).order(
|
|
||||||
// ByteOrder.nativeOrder());
|
|
||||||
// // Log.d("GLMap", "allocate buffer " + size);
|
|
||||||
// fbuf = bbuf.asFloatBuffer();
|
|
||||||
// } else {
|
|
||||||
// fbuf.clear();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// fbuf.put(mFillCoords, 0, 8);
|
|
||||||
// int pos = 4;
|
|
||||||
//
|
|
||||||
// PoolItem last = null, items = null;
|
|
||||||
//
|
|
||||||
// for (PolygonLayer l = layers; l != null; l = l.next) {
|
|
||||||
//
|
|
||||||
// for (PoolItem item = l.pool; item != null; item = item.next) {
|
|
||||||
// fbuf.put(item.vertices, 0, item.used);
|
|
||||||
// last = item;
|
|
||||||
// }
|
|
||||||
// l.offset = pos;
|
|
||||||
// pos += l.verticesCnt;
|
|
||||||
//
|
|
||||||
// if (last != null) {
|
|
||||||
// last.next = items;
|
|
||||||
// items = l.pool;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// l.pool = null;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// VertexPool.add(items);
|
|
||||||
//
|
|
||||||
// fbuf.flip();
|
|
||||||
//
|
|
||||||
// return fbuf;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// static final short[] tmpItem = new short[PoolItem.SIZE];
|
|
||||||
|
|
||||||
// static ShortBuffer compileLayerData(PolygonLayer layers, ShortBuffer buf) {
|
static boolean init() {
|
||||||
// ShortBuffer sbuf = buf;
|
|
||||||
// int size = 4;
|
// Set up the program for rendering polygons
|
||||||
|
polygonProgram = GlUtils.createProgram(Shaders.polygonVertexShader,
|
||||||
|
Shaders.polygonFragmentShader);
|
||||||
|
if (polygonProgram == 0) {
|
||||||
|
// Log.e(TAG, "Could not create polygon program.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
hPolygonMatrix = glGetUniformLocation(polygonProgram, "mvp");
|
||||||
|
hPolygonVertexPosition = glGetAttribLocation(polygonProgram, "a_position");
|
||||||
|
hPolygonColor = glGetUniformLocation(polygonProgram, "u_color");
|
||||||
|
|
||||||
|
mFillPolys = new PolygonLayer[STENCIL_BITS];
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void fillPolygons(int count, double zoom, float scale) {
|
||||||
|
boolean blend = false;
|
||||||
|
|
||||||
|
// draw to framebuffer
|
||||||
|
glColorMask(true, true, true, true);
|
||||||
|
|
||||||
|
// do not modify stencil buffer
|
||||||
|
glStencilMask(0);
|
||||||
|
|
||||||
|
for (int c = 0; c < count; c++) {
|
||||||
|
PolygonLayer l = mFillPolys[c];
|
||||||
|
|
||||||
|
float alpha = 1.0f;
|
||||||
|
|
||||||
|
if (l.area.fade >= zoom || l.area.color[3] != 1.0) {
|
||||||
|
|
||||||
|
if (l.area.fade >= zoom) {
|
||||||
|
alpha = (scale > 1.3f ? scale : 1.3f) - alpha;
|
||||||
|
if (alpha > 1.0f)
|
||||||
|
alpha = 1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
alpha *= l.area.color[3];
|
||||||
|
|
||||||
|
if (!blend) {
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
blend = true;
|
||||||
|
}
|
||||||
|
glUniform4f(hPolygonColor,
|
||||||
|
l.area.color[0], l.area.color[1], l.area.color[2], alpha);
|
||||||
|
|
||||||
|
} else if (l.area.blend == zoom) {
|
||||||
|
alpha = scale - 1.0f;
|
||||||
|
if (alpha > 1.0f)
|
||||||
|
alpha = 1.0f;
|
||||||
|
else if (alpha < 0)
|
||||||
|
alpha = 0;
|
||||||
|
|
||||||
|
glUniform4f(hPolygonColor,
|
||||||
|
l.area.color[0] * (1 - alpha) + l.area.blendColor[0] * alpha,
|
||||||
|
l.area.color[1] * (1 - alpha) + l.area.blendColor[1] * alpha,
|
||||||
|
l.area.color[2] * (1 - alpha) + l.area.blendColor[2] * alpha, 1);
|
||||||
|
} else {
|
||||||
|
if (blend) {
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
blend = false;
|
||||||
|
}
|
||||||
|
if (l.area.blend <= zoom && l.area.blend > 0)
|
||||||
|
glUniform4fv(hPolygonColor, 1, l.area.blendColor, 0);
|
||||||
|
else
|
||||||
|
glUniform4fv(hPolygonColor, 1, l.area.color, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set stencil buffer mask used to draw this layer
|
||||||
|
glStencilFunc(GL_EQUAL, 0xff, 1 << c);
|
||||||
|
|
||||||
|
// draw tile fill coordinates
|
||||||
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blend)
|
||||||
|
glDisable(GL_BLEND);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PolygonLayer drawPolygons(PolygonLayer layer, int next,
|
||||||
|
float[] matrix, double zoom, float scale, short drawCount, boolean clip) {
|
||||||
|
int cnt = 0;
|
||||||
|
|
||||||
|
glUseProgram(polygonProgram);
|
||||||
|
glEnableVertexAttribArray(hPolygonVertexPosition);
|
||||||
|
|
||||||
|
glVertexAttribPointer(hPolygonVertexPosition, 2,
|
||||||
|
GLES20.GL_SHORT, false, 0,
|
||||||
|
POLYGON_VERTICES_DATA_POS_OFFSET);
|
||||||
|
|
||||||
|
glUniformMatrix4fv(hPolygonMatrix, 1, false, matrix, 0);
|
||||||
|
|
||||||
|
glEnable(GL_STENCIL_TEST);
|
||||||
|
|
||||||
|
PolygonLayer l = layer;
|
||||||
|
|
||||||
|
for (; l != null && l.layer < next; l = l.next) {
|
||||||
|
// fade out polygon layers (set in RederTheme)
|
||||||
|
if (l.area.fade > 0 && l.area.fade > zoom)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (cnt == 0) {
|
||||||
|
// disable drawing to framebuffer
|
||||||
|
glColorMask(false, false, false, false);
|
||||||
|
|
||||||
|
// never pass the test, i.e. always apply first stencil op (sfail)
|
||||||
|
glStencilFunc(GL_NEVER, 0, 0xff);
|
||||||
|
|
||||||
|
// clear stencilbuffer
|
||||||
|
glStencilMask(0xFF);
|
||||||
|
// glClear(GL_STENCIL_BUFFER_BIT);
|
||||||
|
|
||||||
|
// clear stencilbuffer (tile region)
|
||||||
|
glStencilOp(GL_ZERO, GL_KEEP, GL_KEEP);
|
||||||
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||||
|
|
||||||
|
// stencil op for stencil method polygon drawing
|
||||||
|
glStencilOp(GL_INVERT, GL_KEEP, GL_KEEP);
|
||||||
|
}
|
||||||
|
|
||||||
|
mFillPolys[cnt] = l;
|
||||||
|
|
||||||
|
// set stencil mask to draw to
|
||||||
|
glStencilMask(1 << cnt++);
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLE_FAN, l.offset, l.verticesCnt);
|
||||||
|
|
||||||
|
// draw up to 8 layers into stencil buffer
|
||||||
|
if (cnt == STENCIL_BITS) {
|
||||||
|
fillPolygons(cnt, zoom, scale);
|
||||||
|
cnt = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cnt > 0)
|
||||||
|
fillPolygons(cnt, zoom, scale);
|
||||||
|
|
||||||
|
glDisable(GL_STENCIL_TEST);
|
||||||
|
|
||||||
|
if (clip) {
|
||||||
|
drawDepthClip(drawCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
// required on GalaxyII, Android 2.3.3 (cant just VAA enable once...)
|
||||||
|
GLES20.glDisableVertexAttribArray(hPolygonVertexPosition);
|
||||||
|
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
|
||||||
|
// static void drawStencilClip(byte drawCount) {
|
||||||
|
// // set stencil mask for line drawing... HACK!!!
|
||||||
|
// glColorMask(false, false, false, false);
|
||||||
//
|
//
|
||||||
// for (PolygonLayer l = layers; l != null; l = l.next)
|
// int c = drawCount % 16;
|
||||||
// size += l.verticesCnt;
|
// // never pass the test, i.e. always apply first stencil op (sfail)
|
||||||
|
// // glStencilFunc(GLES20.GL_NEVER, drawCount, 0);
|
||||||
|
// glStencilFunc(GLES20.GL_NEVER, flipdabit[c], 0);
|
||||||
//
|
//
|
||||||
// size *= NUM_VERTEX_FLOATS;
|
// // replace stencilbuffer
|
||||||
|
// glStencilMask(0xff);
|
||||||
//
|
//
|
||||||
// if (buf == null || buf.capacity() < size) {
|
// // set stencilbuffer for (tile region)
|
||||||
// ByteBuffer bbuf = ByteBuffer.allocateDirect(size * 2).order(
|
// glStencilOp(GLES20.GL_REPLACE, GLES20.GL_KEEP, GLES20.GL_KEEP);
|
||||||
// ByteOrder.nativeOrder());
|
// glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||||
// sbuf = bbuf.asShortBuffer();
|
|
||||||
// } else {
|
|
||||||
// sbuf.clear();
|
|
||||||
// }
|
|
||||||
//
|
//
|
||||||
// short[] data = tmpItem;
|
// glStencilFunc(GL_EQUAL, flipdabit[c], 0xff);
|
||||||
|
// // do not modify stencil buffer
|
||||||
|
// glStencilMask(0);
|
||||||
//
|
//
|
||||||
// if (mByteFillCoords == null) {
|
// glColorMask(true, true, true, true);
|
||||||
// mByteFillCoords = new short[8];
|
|
||||||
// FastMath.convertFloatToHalf(mFillCoords[0], mByteFillCoords, 0);
|
|
||||||
// FastMath.convertFloatToHalf(mFillCoords[1], mByteFillCoords, 1);
|
|
||||||
// FastMath.convertFloatToHalf(mFillCoords[2], mByteFillCoords, 2);
|
|
||||||
// FastMath.convertFloatToHalf(mFillCoords[3], mByteFillCoords, 3);
|
|
||||||
// FastMath.convertFloatToHalf(mFillCoords[4], mByteFillCoords, 4);
|
|
||||||
// FastMath.convertFloatToHalf(mFillCoords[5], mByteFillCoords, 5);
|
|
||||||
// FastMath.convertFloatToHalf(mFillCoords[6], mByteFillCoords, 6);
|
|
||||||
// FastMath.convertFloatToHalf(mFillCoords[7], mByteFillCoords, 7);
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// sbuf.put(mByteFillCoords, 0, 8);
|
|
||||||
// int pos = 4;
|
|
||||||
//
|
|
||||||
// PoolItem last = null, items = null;
|
|
||||||
//
|
|
||||||
// for (PolygonLayer l = layers; l != null; l = l.next) {
|
|
||||||
//
|
|
||||||
// for (PoolItem item = l.pool; item != null; item = item.next) {
|
|
||||||
// PoolItem.toHalfFloat(item, data);
|
|
||||||
// sbuf.put(data, 0, item.used);
|
|
||||||
// last = item;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// l.offset = pos;
|
|
||||||
// pos += l.verticesCnt;
|
|
||||||
//
|
|
||||||
// if (last != null) {
|
|
||||||
// last.next = items;
|
|
||||||
// items = l.pool;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// l.pool = null;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// VertexPool.add(items);
|
|
||||||
//
|
|
||||||
// sbuf.flip();
|
|
||||||
//
|
|
||||||
// return sbuf;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// static void clear(PolygonLayer layers) {
|
|
||||||
// for (PolygonLayer l = layers; l != null; l = l.next) {
|
|
||||||
// if (l.pool != null)
|
|
||||||
// VertexPool.add(l.pool);
|
|
||||||
// }
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
private static short[] mFillCoords;
|
// this only increases the chance for the stencil buffer clip to work
|
||||||
|
// should check for clipping with depth buffer or sth
|
||||||
|
// private static short[] flipdabit = {
|
||||||
|
// 255, 254, 253, 251,
|
||||||
|
// 247, 239, 223, 191,
|
||||||
|
// 127, 63, 252, 250,
|
||||||
|
// 249, 243, 231, 207 };
|
||||||
|
|
||||||
static ShortBuffer compileLayerData(PolygonLayer layers, ShortBuffer buf) {
|
static void drawDepthClip(short drawCount) {
|
||||||
ShortBuffer sbuf = buf;
|
|
||||||
int size = 4;
|
glColorMask(false, false, false, false);
|
||||||
|
glEnable(GLES20.GL_DEPTH_TEST);
|
||||||
|
glEnable(GLES20.GL_POLYGON_OFFSET_FILL);
|
||||||
|
// GLES20.GL_PO
|
||||||
|
GLES20.glPolygonOffset(0, drawCount);
|
||||||
|
|
||||||
|
// int i[] = new int[1];
|
||||||
|
// GLES20.glGetIntegerv(GLES20.GL_POLYGON_OFFSET_UNITS, i, 0);
|
||||||
|
// Log.d("...", "UNITS " + i[0]);
|
||||||
|
//
|
||||||
|
// System.out.println("set offset: " + drawCount);
|
||||||
|
GLES20.glDepthMask(true);
|
||||||
|
|
||||||
|
GLES20.glDepthFunc(GLES20.GL_ALWAYS);
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||||
|
|
||||||
|
GLES20.glDepthMask(false);
|
||||||
|
glColorMask(true, true, true, true);
|
||||||
|
|
||||||
|
GLES20.glDepthFunc(GLES20.GL_EQUAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sizeOf(PolygonLayer layers) {
|
||||||
|
int size = 0;
|
||||||
|
|
||||||
for (PolygonLayer l = layers; l != null; l = l.next)
|
for (PolygonLayer l = layers; l != null; l = l.next)
|
||||||
size += l.verticesCnt;
|
size += l.verticesCnt;
|
||||||
|
|
||||||
size *= NUM_VERTEX_FLOATS;
|
size *= NUM_VERTEX_SHORTS;
|
||||||
|
|
||||||
if (buf == null || buf.capacity() < size) {
|
return size;
|
||||||
ByteBuffer bbuf = ByteBuffer.allocateDirect(size * 2).order(
|
}
|
||||||
ByteOrder.nativeOrder());
|
|
||||||
sbuf = bbuf.asShortBuffer();
|
|
||||||
} else {
|
|
||||||
sbuf.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mFillCoords == null) {
|
static void compileLayerData(PolygonLayer layers, ShortBuffer sbuf) {
|
||||||
short min = (-2) << 4;
|
|
||||||
short max = (short) ((Tile.TILE_SIZE + 1) << 4);
|
|
||||||
mFillCoords = new short[8];
|
|
||||||
mFillCoords[0] = min;
|
|
||||||
mFillCoords[1] = max;
|
|
||||||
mFillCoords[2] = max;
|
|
||||||
mFillCoords[3] = max;
|
|
||||||
mFillCoords[4] = min;
|
|
||||||
mFillCoords[5] = min;
|
|
||||||
mFillCoords[6] = max;
|
|
||||||
mFillCoords[7] = min;
|
|
||||||
}
|
|
||||||
|
|
||||||
sbuf.put(mFillCoords, 0, 8);
|
|
||||||
int pos = 4;
|
int pos = 4;
|
||||||
|
|
||||||
ShortItem last = null, items = null;
|
ShortItem last = null, items = null;
|
||||||
@ -203,10 +300,6 @@ class PolygonLayers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ShortPool.add(items);
|
ShortPool.add(items);
|
||||||
|
|
||||||
sbuf.flip();
|
|
||||||
|
|
||||||
return sbuf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clear(PolygonLayer layers) {
|
static void clear(PolygonLayer layers) {
|
||||||
|
|||||||
@ -16,166 +16,141 @@
|
|||||||
package org.mapsforge.android.glrenderer;
|
package org.mapsforge.android.glrenderer;
|
||||||
|
|
||||||
class Shaders {
|
class Shaders {
|
||||||
final static String gLineVertexShader = ""
|
|
||||||
|
final static String lineVertexShader = ""
|
||||||
+ "precision mediump float; \n"
|
+ "precision mediump float; \n"
|
||||||
+ "uniform mat4 u_center;"
|
+ "uniform mat4 mvp;"
|
||||||
+ "attribute vec4 a_position;"
|
+ "attribute vec4 a_position;"
|
||||||
+ "attribute vec2 a_st;"
|
+ "attribute vec2 a_st;"
|
||||||
+ "varying vec2 v_st;"
|
+ "varying vec2 v_st;"
|
||||||
+ "const vec4 scale = vec4(1.0/16.0, 1.0/16.0, 0.0, 1.0);"
|
+ "uniform float u_width;"
|
||||||
|
+ "uniform float u_offset;"
|
||||||
|
+ "const float dscale = 8.0/1000.0;"
|
||||||
+ "void main() {"
|
+ "void main() {"
|
||||||
// + " gl_Position = u_center * vec4(a_position.x, a_position.y, 0.0, 1.0);"
|
+ " vec2 dir = dscale * u_width * a_position.zw;"
|
||||||
// + " v_st = a_position.zw;"
|
+ " gl_Position = mvp * vec4(a_position.xy + dir, 0.0,1.0);"
|
||||||
+ " gl_Position = u_center * (scale * a_position);"
|
+ " v_st = u_width * a_st;"
|
||||||
// + " gl_Position = u_center * a_position;"
|
|
||||||
+ " v_st = 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"
|
+ "#extension GL_OES_standard_derivatives : enable\n"
|
||||||
+ "precision mediump float;"
|
+ "precision mediump float;\n"
|
||||||
+ "uniform lowp vec2 u_mode;"
|
+ "uniform float u_wscale;"
|
||||||
|
+ "uniform float u_width;"
|
||||||
+ "uniform vec4 u_color;"
|
+ "uniform vec4 u_color;"
|
||||||
+ "const lowp float zero = 0.0;"
|
|
||||||
+ "const float fuzzf = 1.8;"
|
|
||||||
+ "varying vec2 v_st;"
|
+ "varying vec2 v_st;"
|
||||||
|
+ "const float zero = 0.0;"
|
||||||
+ "void main() {"
|
+ "void main() {"
|
||||||
+ " lowp vec4 color = u_color;"
|
+ " vec4 color = u_color;"
|
||||||
+ " lowp float len;"
|
+ " float width = u_width;"
|
||||||
+ " lowp float fuzz;"
|
+ " float len;"
|
||||||
+ " lowp float width = u_mode[1];"
|
+ " if (v_st.t == zero)"
|
||||||
// + " if (v_st.t == zero){ "
|
+ " len = abs(v_st.s);"
|
||||||
// + " fuzz = fwidth(v_st.s) * fuzzf;"
|
+ " else "
|
||||||
// + " len = width - abs(v_st.s);"
|
+ " len = length(v_st);"
|
||||||
// + " } else {"
|
// + " if (u_width - len < 2.0){"
|
||||||
+ " fuzz = max(fwidth(v_st.s), fwidth(v_st.t)) * fuzzf;"
|
+ " vec2 st_width = fwidth(v_st);"
|
||||||
+ " len = width - length(v_st);"
|
+ " float fuzz = max(st_width.s, st_width.t) * 1.5;"
|
||||||
// + " } "
|
+ " color.a *= smoothstep(zero, fuzz + u_wscale, u_width - len);"
|
||||||
// + " if (len < min_fuzz)"
|
// + " }"
|
||||||
// + " discard;"
|
|
||||||
// + " alpha = zero;"
|
|
||||||
+ " if (len < fuzz) {"
|
|
||||||
+ " lowp float min_fuzz = -fuzz * u_mode[0];"
|
|
||||||
+ " color.a *= smoothstep(min_fuzz, fuzz, len);"
|
|
||||||
// + " if (color.a == 0.0 ) color = vec4(1.0,0.0,0.0,1.0);"
|
|
||||||
+ " }"
|
|
||||||
+ " gl_FragColor = color;"
|
+ " gl_FragColor = color;"
|
||||||
+ "}";
|
+ "}";
|
||||||
|
|
||||||
// final static String gLineFragmentShader = ""
|
final static String polygonVertexShader = ""
|
||||||
// + "#extension GL_OES_standard_derivatives : enable\n"
|
|
||||||
// + "#pragma profilepragma blendoperation(gl_FragColor, GL_FUNC_ADD, GL_ONE, GL_ONE_MINUS_SRC_ALPHA)\n"
|
|
||||||
// + "precision mediump float;"
|
|
||||||
// + "uniform vec2 u_mode;"
|
|
||||||
// + "uniform vec4 u_color;"
|
|
||||||
// + "const float zero = 0.0;"
|
|
||||||
// + "const vec4 blank = vec4(0.0,0.0,0.0,0.0);"
|
|
||||||
// + "varying vec2 v_st;"
|
|
||||||
// + "void main() {"
|
|
||||||
// + "lowp color = u_color;"
|
|
||||||
// + "lowp alpha = 1.0;"
|
|
||||||
// + "float width = u_mode[1];"
|
|
||||||
// + " if (v_st.t == zero){ "
|
|
||||||
// + " float fuzz = fwidth(v_st.s) * 1.5;"
|
|
||||||
// + " float min_fuzz = -fuzz * u_mode[0];"
|
|
||||||
// + " float len = width - abs(v_st.s);"
|
|
||||||
// // + " if (len > fuzz)"
|
|
||||||
// // + " gl_FragColor = u_color;"
|
|
||||||
// // + " else if (len < min_fuzz)"
|
|
||||||
// // + " gl_FragColor = blank;"
|
|
||||||
// // + " else"
|
|
||||||
// + " gl_FragColor = u_color * smoothstep(min_fuzz, fuzz, len);"
|
|
||||||
// + " } else {"
|
|
||||||
// + " float fuzz = max(fwidth(v_st.s), fwidth(v_st.t)) * 1.5;"
|
|
||||||
// + " gl_FragColor = u_color * smoothstep(-fuzz * u_mode[0], fuzz, width - length(v_st));"
|
|
||||||
// + " } "
|
|
||||||
// + "glFragColor = color"
|
|
||||||
// + "}";
|
|
||||||
|
|
||||||
// final static String gLineFragmentShader = ""
|
|
||||||
// + "#extension GL_OES_standard_derivatives : enable\n"
|
|
||||||
// + "precision mediump float;"
|
|
||||||
// + "uniform float u_width;"
|
|
||||||
// + "uniform vec2 u_mode;"
|
|
||||||
// + "uniform vec4 u_color;"
|
|
||||||
// + "const float zero = 0.0;"
|
|
||||||
// // + "const vec4 blank = vec4(1.0, 0.0, 0.0, 1.0);"
|
|
||||||
// + "varying vec2 v_st;"
|
|
||||||
// + "void main() {"
|
|
||||||
// + "float width = u_mode[1];"
|
|
||||||
// // + "float alpha = 1.0;"
|
|
||||||
// + " if (u_mode[0] == zero) {"
|
|
||||||
// // + " gl_FragColor = u_color;"
|
|
||||||
// // + " float fuzz;"
|
|
||||||
// // + " float len;"
|
|
||||||
// + " if (v_st.t == zero){ "
|
|
||||||
// // + " fuzz = - sqrt(dFdx(v_st.s) * dFdx(v_st.s) + dFdy(v_st.s) * dFdy(v_st.s));"
|
|
||||||
// + " float fuzz = -fwidth(v_st.s) * 1.5;"
|
|
||||||
// + " float len = abs(v_st.s) - width;"
|
|
||||||
// // + " if (len < fuzz)"
|
|
||||||
// + " gl_FragColor = u_color * smoothstep(zero, fuzz, len);"
|
|
||||||
// + " } else {"
|
|
||||||
// + " float fuzz = -max(fwidth(v_st.s), fwidth(v_st.t)) * 1.5;"
|
|
||||||
// + " float len = length(v_st) - width;"
|
|
||||||
// // + " if (len < fuzz)"
|
|
||||||
// + " gl_FragColor = u_color * smoothstep(zero, fuzz, len);"
|
|
||||||
// + " } "
|
|
||||||
// // + " if (len > zero)"
|
|
||||||
// // + " gl_FragColor = blank;"
|
|
||||||
// // + " discard;"
|
|
||||||
// // + " gl_FragColor = u_color;"
|
|
||||||
// // + " else if (len < fuzz)"
|
|
||||||
// // + " gl_FragColor = blank2;"
|
|
||||||
// // + " else "
|
|
||||||
// + " } else { "
|
|
||||||
// + " float fuzz = fwidth(v_st.s);"
|
|
||||||
// // + " gl_FragColor = u_color * smoothstep(fuzz, zero, abs(v_st.s) - u_width + fuzz);"
|
|
||||||
// // + " fuzz = - sqrt(dFdx(v_st.s) * dFdx(v_st.s) + dFdy(v_st.s) * dFdy(v_st.s)) * 1.5;"
|
|
||||||
// + " gl_FragColor = u_color * smoothstep(fuzz*0.5, -fuzz, abs(v_st.s) - width);"
|
|
||||||
// + " }"
|
|
||||||
// + "}";
|
|
||||||
//
|
|
||||||
// final static String gLineFragmentShader = "" +
|
|
||||||
// "#extension GL_OES_standard_derivatives : enable\n" +
|
|
||||||
// "precision mediump float;" +
|
|
||||||
// "uniform int u_mode;" +
|
|
||||||
// "uniform vec4 u_color;" +
|
|
||||||
// "varying vec2 v_st;" +
|
|
||||||
// "void main() {" +
|
|
||||||
// " gl_FragColor = u_color;" +
|
|
||||||
// "}";
|
|
||||||
|
|
||||||
final static String gLineFragmentShaderSimple = ""
|
|
||||||
+ "precision mediump float;"
|
+ "precision mediump float;"
|
||||||
+ "uniform vec4 u_color;"
|
+ "uniform mat4 mvp;"
|
||||||
+ "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"
|
|
||||||
+ "attribute vec4 a_position;"
|
+ "attribute vec4 a_position;"
|
||||||
+ "const vec4 scale = vec4(1.0/16.0, 1.0/16.0, 0.0, 1.0);"
|
+ "uniform float u_offset;"
|
||||||
+ "void main() {"
|
+ "void main() {"
|
||||||
+ " gl_Position = u_center * (scale * a_position);"
|
+ " gl_Position = mvp * a_position;"
|
||||||
+ "}";
|
+ "}";
|
||||||
|
|
||||||
final static String gPolygonFragmentShader = ""
|
final static String polygonFragmentShader = ""
|
||||||
+ "precision mediump float;"
|
+ "precision mediump float;"
|
||||||
+ "uniform vec4 u_color;"
|
+ "uniform vec4 u_color;"
|
||||||
+ "void main() {"
|
+ "void main() {"
|
||||||
+ " gl_FragColor = u_color;"
|
+ " gl_FragColor = u_color;"
|
||||||
+ "}";
|
+ "}";
|
||||||
|
|
||||||
|
final static String textVertexShader = ""
|
||||||
|
+ "precision highp float; "
|
||||||
|
+ "attribute vec4 vertex;"
|
||||||
|
+ "attribute vec2 tex_coord;"
|
||||||
|
+ "uniform mat4 mvp;"
|
||||||
|
+ "uniform float scale;"
|
||||||
|
+ "varying vec2 tex_c;"
|
||||||
|
+ "const vec2 div = vec2(1.0/4096.0,1.0/2048.0);"
|
||||||
|
+ "void main() {"
|
||||||
|
+ " gl_Position = mvp * vec4(vertex.xy + (vertex.zw / scale), 0.0, 1.0);"
|
||||||
|
+ " tex_c = tex_coord * div;"
|
||||||
|
+ "}";
|
||||||
|
|
||||||
|
final static String textFragmentShader = ""
|
||||||
|
+ "precision highp float;"
|
||||||
|
+ "uniform sampler2D tex;"
|
||||||
|
+ "uniform vec4 col;"
|
||||||
|
+ "varying vec2 tex_c;"
|
||||||
|
+ "void main() {"
|
||||||
|
+ " gl_FragColor = texture2D(tex, tex_c.xy);"
|
||||||
|
+ "}";
|
||||||
|
|
||||||
|
// final static String lineVertexZigZagShader = ""
|
||||||
|
// + "precision mediump float; \n"
|
||||||
|
// + "uniform mat4 mvp;"
|
||||||
|
// + "attribute vec4 a_pos1;"
|
||||||
|
// + "attribute vec2 a_st1;"
|
||||||
|
// + "attribute vec4 a_pos2;"
|
||||||
|
// + "attribute vec2 a_st2;"
|
||||||
|
// + "varying vec2 v_st;"
|
||||||
|
// + "uniform vec2 u_mode;"
|
||||||
|
// + "const float dscale = 1.0/1000.0;"
|
||||||
|
// + "void main() {"
|
||||||
|
// + "if (gl_VertexID & 1 == 0) {"
|
||||||
|
// + " vec2 dir = dscale * u_mode[1] * a_pos1.zw;"
|
||||||
|
// + " gl_Position = mvp * vec4(a_pos1.xy + dir, 0.0,1.0);"
|
||||||
|
// + " v_st = u_mode[1] * a_st1;"
|
||||||
|
// + "} else {"
|
||||||
|
// + " vec2 dir = dscale * u_mode[1] * a_pos2.zw;"
|
||||||
|
// + " gl_Position = mvp * vec4( a_pos1.xy, dir, 0.0,1.0);"
|
||||||
|
// + " v_st = u_mode[1] * vec2(-a_st2.s , a_st2.t);"
|
||||||
|
// + "}";
|
||||||
|
|
||||||
|
// final static String lineFragmentShader = ""
|
||||||
|
// + "#extension GL_OES_standard_derivatives : enable\n"
|
||||||
|
// + "precision mediump float;\n"
|
||||||
|
// + "uniform vec2 u_mode;"
|
||||||
|
// + "uniform vec4 u_color;"
|
||||||
|
// + "varying vec2 v_st;"
|
||||||
|
// + "const float zero = 0.0;"
|
||||||
|
// + "void main() {"
|
||||||
|
// + " vec4 color = u_color;"
|
||||||
|
// + " float width = u_mode[1];"
|
||||||
|
// + " float len;"
|
||||||
|
// + " if (v_st.t == zero)"
|
||||||
|
// + " len = abs(v_st.s);"
|
||||||
|
// + " else "
|
||||||
|
// + " len = length(v_st);"
|
||||||
|
// + " vec2 st_width = fwidth(v_st);"
|
||||||
|
// + " float fuzz = max(st_width.s, st_width.t);"
|
||||||
|
// + " color.a *= smoothstep(-pixel, fuzz*pixel, width - (len * width));"
|
||||||
|
// + " gl_FragColor = color;"
|
||||||
|
// + "}";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,5 +24,6 @@ public class ShortItem {
|
|||||||
used = 0;
|
used = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int SIZE = 128;
|
// must be multiple of 6 and 4 (expected in LineLayer/PolygonLayer)
|
||||||
|
static final int SIZE = 240;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,59 +14,80 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapsforge.android.glrenderer;
|
package org.mapsforge.android.glrenderer;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.util.Log;
|
||||||
|
|
||||||
public class ShortPool {
|
public class ShortPool {
|
||||||
private static final int POOL_LIMIT = 8192;
|
private static final int POOL_LIMIT = 6000;
|
||||||
|
|
||||||
@SuppressLint("UseValueOf")
|
|
||||||
private static final Boolean lock = new Boolean(true);
|
|
||||||
|
|
||||||
static private ShortItem pool = null;
|
static private ShortItem pool = null;
|
||||||
static private int count = 0;
|
static private int count = 0;
|
||||||
|
static private int countAll = 0;
|
||||||
|
|
||||||
static ShortItem get() {
|
static synchronized void finish() {
|
||||||
synchronized (lock) {
|
count = 0;
|
||||||
|
countAll = 0;
|
||||||
if (count == 0)
|
pool = null;
|
||||||
return new ShortItem();
|
|
||||||
|
|
||||||
count--;
|
|
||||||
|
|
||||||
ShortItem it = pool;
|
|
||||||
pool = pool.next;
|
|
||||||
it.used = 0;
|
|
||||||
it.next = null;
|
|
||||||
return it;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
if (items == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
synchronized (lock) {
|
// limit pool items
|
||||||
|
if (countAll < POOL_LIMIT) {
|
||||||
|
|
||||||
ShortItem last = items;
|
ShortItem last = items;
|
||||||
|
|
||||||
// limit pool items
|
while (true) {
|
||||||
while (count < POOL_LIMIT) {
|
|
||||||
if (last.next == null) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
last = last.next;
|
|
||||||
count++;
|
count++;
|
||||||
}
|
|
||||||
|
|
||||||
// clear references
|
if (last.next == null)
|
||||||
ShortItem tmp2, tmp = last.next;
|
break;
|
||||||
while (tmp != null) {
|
|
||||||
tmp2 = tmp;
|
last = last.next;
|
||||||
tmp = tmp.next;
|
|
||||||
tmp2.next = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
last.next = pool;
|
last.next = pool;
|
||||||
pool = items;
|
pool = items;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// int cleared = 0;
|
||||||
|
ShortItem prev, tmp = items;
|
||||||
|
while (tmp != null) {
|
||||||
|
prev = tmp;
|
||||||
|
tmp = tmp.next;
|
||||||
|
|
||||||
|
countAll--;
|
||||||
|
|
||||||
|
prev.next = null;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,6 +15,7 @@
|
|||||||
package org.mapsforge.android.glrenderer;
|
package org.mapsforge.android.glrenderer;
|
||||||
|
|
||||||
import org.mapsforge.android.rendertheme.renderinstruction.Caption;
|
import org.mapsforge.android.rendertheme.renderinstruction.Caption;
|
||||||
|
import org.mapsforge.android.rendertheme.renderinstruction.PathText;
|
||||||
|
|
||||||
public class TextItem {
|
public class TextItem {
|
||||||
TextItem next;
|
TextItem next;
|
||||||
@ -22,14 +23,27 @@ public class TextItem {
|
|||||||
final float x, y;
|
final float x, y;
|
||||||
final String text;
|
final String text;
|
||||||
final Caption caption;
|
final Caption caption;
|
||||||
|
final PathText path;
|
||||||
final float width;
|
final float width;
|
||||||
|
|
||||||
|
short x1, y1, x2, y2;
|
||||||
|
|
||||||
public TextItem(float x, float y, String text, Caption caption) {
|
public TextItem(float x, float y, String text, Caption caption) {
|
||||||
this.x = x;
|
this.x = x;
|
||||||
this.y = y;
|
this.y = y;
|
||||||
this.text = text;
|
this.text = text;
|
||||||
this.caption = caption;
|
this.caption = caption;
|
||||||
this.width = caption.paint.measureText(text);
|
this.width = caption.paint.measureText(text);
|
||||||
|
this.path = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextItem(float x, float y, String text, PathText pathText, float width) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.text = text;
|
||||||
|
this.path = pathText;
|
||||||
|
this.caption = null;
|
||||||
|
this.width = width;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2010, 2011, 2012 mapsforge.org
|
* Copyright 2012 Hannes Janetzek
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify it under the
|
* This program is free software: you can redistribute it and/or modify it under the
|
||||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
@ -26,58 +26,59 @@ import android.graphics.Color;
|
|||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.opengl.GLES20;
|
import android.opengl.GLES20;
|
||||||
import android.opengl.GLUtils;
|
import android.opengl.GLUtils;
|
||||||
|
import android.util.FloatMath;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
public class TextRenderer {
|
public class TextRenderer {
|
||||||
private final static int TEXTURE_WIDTH = 512;
|
private final static int TEXTURE_WIDTH = 512;
|
||||||
private final static int TEXTURE_HEIGHT = 256;
|
private final static int TEXTURE_HEIGHT = 256;
|
||||||
|
private final static float SCALE_FACTOR = 8.0f;
|
||||||
|
|
||||||
final static int MAX_LABELS = 30;
|
final static int INDICES_PER_SPRITE = 6;
|
||||||
|
final static int VERTICES_PER_SPRITE = 4;
|
||||||
private final Bitmap mBitmap;
|
|
||||||
private final Canvas mCanvas;
|
|
||||||
private int mFontPadX = 1;
|
|
||||||
private int mFontPadY = 1;
|
|
||||||
private int mBitmapFormat;
|
|
||||||
private int mBitmapType;
|
|
||||||
private ByteBuffer mByteBuffer;
|
|
||||||
private ShortBuffer mShortBuffer;
|
|
||||||
private TextTexture[] mTextures;
|
|
||||||
|
|
||||||
private int mIndicesVBO;
|
|
||||||
private int mVerticesVBO;
|
|
||||||
|
|
||||||
final static int INDICES_PER_SPRITE = 6; // Indices Per Sprite
|
|
||||||
final static int VERTICES_PER_SPRITE = 4; // Vertices Per Sprite
|
|
||||||
final static int SHORTS_PER_VERTICE = 6;
|
final static int SHORTS_PER_VERTICE = 6;
|
||||||
|
final static int MAX_LABELS = 35;
|
||||||
|
|
||||||
|
private static Bitmap mBitmap;
|
||||||
|
private static Canvas mCanvas;
|
||||||
|
private static int mFontPadX = 1;
|
||||||
|
private static int mFontPadY = 1;
|
||||||
|
private static int mBitmapFormat;
|
||||||
|
private static int mBitmapType;
|
||||||
|
private static ByteBuffer mByteBuffer;
|
||||||
|
private static ShortBuffer mShortBuffer;
|
||||||
|
private static TextTexture[] mTextures;
|
||||||
|
|
||||||
|
private static int mIndicesVBO;
|
||||||
|
private static int mVerticesVBO;
|
||||||
|
|
||||||
private static int mTextProgram;
|
private static int mTextProgram;
|
||||||
static int hTextUVPMatrix;
|
private static int hTextUVPMatrix;
|
||||||
static int hTextVertex;
|
private static int hTextVertex;
|
||||||
static int hTextScale;
|
private static int hTextScale;
|
||||||
static int hTextTextureCoord;
|
private static int hTextTextureCoord;
|
||||||
static int hTextUColor;
|
// private static int hTextUColor;
|
||||||
|
|
||||||
static Paint mPaint = new Paint(Color.BLACK);
|
static Paint mPaint = new Paint(Color.BLACK);
|
||||||
|
|
||||||
boolean debug = false;
|
private static boolean debug = false;
|
||||||
short[] debugVertices = {
|
private static short[] debugVertices = {
|
||||||
|
|
||||||
0, 0,
|
0, 0,
|
||||||
0, TEXTURE_HEIGHT,
|
0, TEXTURE_HEIGHT * 4,
|
||||||
|
|
||||||
0, TEXTURE_HEIGHT - 1,
|
0, TEXTURE_HEIGHT - 1,
|
||||||
0, 0,
|
0, 0,
|
||||||
|
|
||||||
TEXTURE_WIDTH - 1, 0,
|
TEXTURE_WIDTH - 1, 0,
|
||||||
TEXTURE_WIDTH, TEXTURE_HEIGHT,
|
TEXTURE_WIDTH * 4, TEXTURE_HEIGHT * 4,
|
||||||
|
|
||||||
TEXTURE_WIDTH - 1, TEXTURE_HEIGHT - 1,
|
TEXTURE_WIDTH - 1, TEXTURE_HEIGHT - 1,
|
||||||
TEXTURE_WIDTH, 0,
|
TEXTURE_WIDTH * 4, 0,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
TextRenderer(int numTextures) {
|
static boolean init(int numTextures) {
|
||||||
mBitmap = Bitmap
|
mBitmap = Bitmap
|
||||||
.createBitmap(TEXTURE_WIDTH, TEXTURE_HEIGHT, Bitmap.Config.ARGB_8888);
|
.createBitmap(TEXTURE_WIDTH, TEXTURE_HEIGHT, Bitmap.Config.ARGB_8888);
|
||||||
mCanvas = new Canvas(mBitmap);
|
mCanvas = new Canvas(mBitmap);
|
||||||
@ -85,15 +86,14 @@ public class TextRenderer {
|
|||||||
mBitmapFormat = GLUtils.getInternalFormat(mBitmap);
|
mBitmapFormat = GLUtils.getInternalFormat(mBitmap);
|
||||||
mBitmapType = GLUtils.getType(mBitmap);
|
mBitmapType = GLUtils.getType(mBitmap);
|
||||||
|
|
||||||
mTextProgram = GlUtils.createProgram(textVertexShader, textFragmentShader);
|
mTextProgram = GlUtils.createProgram(Shaders.textVertexShader,
|
||||||
|
Shaders.textFragmentShader);
|
||||||
|
|
||||||
hTextUVPMatrix = GLES20.glGetUniformLocation(mTextProgram, "mvp");
|
hTextUVPMatrix = GLES20.glGetUniformLocation(mTextProgram, "mvp");
|
||||||
hTextUColor = GLES20.glGetUniformLocation(mTextProgram, "col");
|
|
||||||
hTextVertex = GLES20.glGetAttribLocation(mTextProgram, "vertex");
|
hTextVertex = GLES20.glGetAttribLocation(mTextProgram, "vertex");
|
||||||
hTextScale = GLES20.glGetUniformLocation(mTextProgram, "scale");
|
hTextScale = GLES20.glGetUniformLocation(mTextProgram, "scale");
|
||||||
hTextTextureCoord = GLES20.glGetAttribLocation(mTextProgram, "tex_coord");
|
hTextTextureCoord = GLES20.glGetAttribLocation(mTextProgram, "tex_coord");
|
||||||
|
|
||||||
// mVertexBuffer = new float[];
|
|
||||||
int bufferSize = numTextures
|
int bufferSize = numTextures
|
||||||
* MAX_LABELS * VERTICES_PER_SPRITE
|
* MAX_LABELS * VERTICES_PER_SPRITE
|
||||||
* SHORTS_PER_VERTICE * (Short.SIZE / 8);
|
* SHORTS_PER_VERTICE * (Short.SIZE / 8);
|
||||||
@ -121,12 +121,12 @@ public class TextRenderer {
|
|||||||
GLES20.GL_CLAMP_TO_EDGE); // Set V Wrapping
|
GLES20.GL_CLAMP_TO_EDGE); // Set V Wrapping
|
||||||
|
|
||||||
// load the generated bitmap onto the texture
|
// load the generated bitmap onto the texture
|
||||||
// GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, mBitmap, 0);
|
|
||||||
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, mBitmapFormat, mBitmap,
|
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, mBitmapFormat, mBitmap,
|
||||||
mBitmapType, 0);
|
mBitmapType, 0);
|
||||||
|
|
||||||
textures[i] = new TextTexture(textureIds[i]);
|
textures[i] = new TextTexture(textureIds[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
GlUtils.checkGlError("init textures");
|
GlUtils.checkGlError("init textures");
|
||||||
|
|
||||||
mTextures = textures;
|
mTextures = textures;
|
||||||
@ -136,12 +136,18 @@ public class TextRenderer {
|
|||||||
int len = indices.length;
|
int len = indices.length;
|
||||||
short j = 0;
|
short j = 0;
|
||||||
for (int i = 0; i < len; i += INDICES_PER_SPRITE, j += VERTICES_PER_SPRITE) {
|
for (int i = 0; i < len; i += INDICES_PER_SPRITE, j += VERTICES_PER_SPRITE) {
|
||||||
|
// indices[i + 0] = (short) (j + 0);
|
||||||
|
// indices[i + 1] = (short) (j + 1);
|
||||||
|
// indices[i + 2] = (short) (j + 2);
|
||||||
|
// indices[i + 3] = (short) (j + 2);
|
||||||
|
// indices[i + 4] = (short) (j + 3);
|
||||||
|
// indices[i + 5] = (short) (j + 0);
|
||||||
indices[i + 0] = (short) (j + 0);
|
indices[i + 0] = (short) (j + 0);
|
||||||
indices[i + 1] = (short) (j + 1);
|
indices[i + 1] = (short) (j + 0);
|
||||||
indices[i + 2] = (short) (j + 2);
|
indices[i + 2] = (short) (j + 1);
|
||||||
indices[i + 3] = (short) (j + 2);
|
indices[i + 3] = (short) (j + 3);
|
||||||
indices[i + 4] = (short) (j + 3);
|
indices[i + 4] = (short) (j + 2);
|
||||||
indices[i + 5] = (short) (j + 0);
|
indices[i + 5] = (short) (j + 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
ShortBuffer tmpIndices = mByteBuffer.asShortBuffer();
|
ShortBuffer tmpIndices = mByteBuffer.asShortBuffer();
|
||||||
@ -151,21 +157,25 @@ public class TextRenderer {
|
|||||||
|
|
||||||
int[] mVboIds = new int[2];
|
int[] mVboIds = new int[2];
|
||||||
GLES20.glGenBuffers(2, mVboIds, 0);
|
GLES20.glGenBuffers(2, mVboIds, 0);
|
||||||
|
|
||||||
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, mVboIds[0]);
|
|
||||||
GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER, len * (Short.SIZE / 8),
|
|
||||||
tmpIndices,
|
|
||||||
GLES20.GL_STATIC_DRAW);
|
|
||||||
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
|
|
||||||
|
|
||||||
mIndicesVBO = mVboIds[0];
|
mIndicesVBO = mVboIds[0];
|
||||||
mVerticesVBO = mVboIds[1];
|
mVerticesVBO = mVboIds[1];
|
||||||
|
|
||||||
|
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, mIndicesVBO);
|
||||||
|
GLES20.glBufferData(GLES20.GL_ELEMENT_ARRAY_BUFFER, len * (Short.SIZE / 8),
|
||||||
|
tmpIndices, GLES20.GL_STATIC_DRAW);
|
||||||
|
GLES20.glBindBuffer(GLES20.GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||||
|
|
||||||
|
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mVerticesVBO);
|
||||||
|
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, bufferSize,
|
||||||
|
mShortBuffer, GLES20.GL_DYNAMIC_DRAW);
|
||||||
|
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean drawToTexture(GLMapTile tile) {
|
static boolean drawToTexture(GLMapTile tile) {
|
||||||
TextTexture tex = null;
|
TextTexture tex = null;
|
||||||
|
|
||||||
if (tile.labels.size() == 0)
|
if (tile.labels == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for (int i = 0; i < mTextures.length; i++) {
|
for (int i = 0; i < mTextures.length; i++) {
|
||||||
@ -194,9 +204,7 @@ public class TextRenderer {
|
|||||||
float x = mFontPadX;
|
float x = mFontPadX;
|
||||||
float width, height;
|
float width, height;
|
||||||
|
|
||||||
int max = tile.labels.size();
|
int max = MAX_LABELS;
|
||||||
if (max > MAX_LABELS)
|
|
||||||
max = MAX_LABELS;
|
|
||||||
|
|
||||||
if (debug) {
|
if (debug) {
|
||||||
mCanvas.drawLine(debugVertices[0], debugVertices[1], debugVertices[4],
|
mCanvas.drawLine(debugVertices[0], debugVertices[1], debugVertices[4],
|
||||||
@ -212,10 +220,18 @@ public class TextRenderer {
|
|||||||
|
|
||||||
int advanceY = 0;
|
int advanceY = 0;
|
||||||
|
|
||||||
for (int i = 0; i < max; i++) {
|
TextItem t = tile.labels;
|
||||||
TextItem t = tile.labels.get(i);
|
float yy;
|
||||||
|
short x1, x2, x3, x4, y1, y2, y3, y4;
|
||||||
|
|
||||||
|
for (int i = 0; t != null && i < max; t = t.next, i++) {
|
||||||
|
|
||||||
|
if (t.caption != null) {
|
||||||
|
height = (int) (t.caption.fontHeight) + 2 * mFontPadY;
|
||||||
|
} else {
|
||||||
|
height = (int) (t.path.fontHeight) + 2 * mFontPadY;
|
||||||
|
}
|
||||||
|
|
||||||
height = (int) (t.caption.fontHeight) + 2 * mFontPadY;
|
|
||||||
width = t.width + 2 * mFontPadX;
|
width = t.width + 2 * mFontPadX;
|
||||||
|
|
||||||
if (height > advanceY)
|
if (height > advanceY)
|
||||||
@ -227,45 +243,71 @@ public class TextRenderer {
|
|||||||
advanceY = (int) height;
|
advanceY = (int) height;
|
||||||
}
|
}
|
||||||
|
|
||||||
float yy = y + (height - 1) - t.caption.fontDescent - mFontPadY;
|
if (t.caption != null) {
|
||||||
|
yy = y + (height - 1) - t.caption.fontDescent - mFontPadY;
|
||||||
|
} else {
|
||||||
|
yy = y + (height - 1) - t.path.fontDescent - mFontPadY;
|
||||||
|
}
|
||||||
|
|
||||||
if (yy > TEXTURE_HEIGHT) {
|
if (yy > TEXTURE_HEIGHT) {
|
||||||
Log.d(TAG, "reached max labels");
|
Log.d(TAG, "reached max labels");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t.caption.stroke != null)
|
if (t.caption != null) {
|
||||||
mCanvas.drawText(t.text, x + t.width / 2, yy, t.caption.stroke);
|
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);
|
mCanvas.drawText(t.text, x + t.width / 2, yy, t.caption.paint);
|
||||||
|
} else {
|
||||||
// Log.d(TAG, "draw: " + t.text + " at:" + (xx + t.width / 2) + " " + yy + " w:"
|
if (t.path.stroke != null)
|
||||||
// + t.width + " " + cellHeight);
|
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)
|
if (width > TEXTURE_WIDTH)
|
||||||
width = TEXTURE_WIDTH;
|
width = TEXTURE_WIDTH;
|
||||||
|
|
||||||
float halfWidth = width / 2.0f;
|
float hw = width / 2.0f;
|
||||||
float halfHeight = height / 2.0f;
|
float hh = height / 2.0f;
|
||||||
|
|
||||||
// short x1 = (short) (2.0f * (t.x - halfWidth));
|
if (t.caption != null) {
|
||||||
// short y1 = (short) (2.0f * (t.y - halfHeight));
|
x1 = x3 = (short) (SCALE_FACTOR * (-hw));
|
||||||
// short x2 = (short) (2.0f * (t.x + halfWidth));
|
y1 = y3 = (short) (SCALE_FACTOR * (-hh));
|
||||||
// short y2 = (short) (2.0f * (t.y + halfHeight));
|
x2 = x4 = (short) (SCALE_FACTOR * (hw));
|
||||||
|
y2 = y4 = (short) (SCALE_FACTOR * (hh));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
float vx = t.x1 - t.x2;
|
||||||
|
float vy = t.y1 - t.y2;
|
||||||
|
float a = FloatMath.sqrt(vx * vx + vy * vy);
|
||||||
|
vx = vx / a;
|
||||||
|
vy = vy / a;
|
||||||
|
|
||||||
short x1 = (short) (2.0f * (-halfWidth));
|
float ux = -vy;
|
||||||
short y1 = (short) (2.0f * (-halfHeight));
|
float uy = vx;
|
||||||
short x2 = (short) (2.0f * (halfWidth));
|
|
||||||
short y2 = (short) (2.0f * (halfHeight));
|
|
||||||
|
|
||||||
short u1 = (short) (2.0f * x);
|
x1 = (short) (SCALE_FACTOR * (vx * hw + ux * hh));
|
||||||
short v1 = (short) (2.0f * y);
|
y1 = (short) (SCALE_FACTOR * (vy * hw + uy * hh));
|
||||||
short u2 = (short) (2.0f * (x + width));
|
|
||||||
short v2 = (short) (2.0f * (y + height));
|
|
||||||
|
|
||||||
short tx = (short) (2.0f * t.x);
|
x2 = (short) (SCALE_FACTOR * (-vx * hw + ux * hh));
|
||||||
short ty = (short) (2.0f * t.y);
|
y3 = (short) (SCALE_FACTOR * (-vy * hw + uy * hh));
|
||||||
|
|
||||||
|
x4 = (short) (SCALE_FACTOR * (-vx * hw - ux * hh));
|
||||||
|
y4 = (short) (SCALE_FACTOR * (-vy * hw - uy * hh));
|
||||||
|
|
||||||
|
x3 = (short) (SCALE_FACTOR * (vx * hw - ux * hh));
|
||||||
|
y2 = (short) (SCALE_FACTOR * (vy * hw - uy * hh));
|
||||||
|
|
||||||
|
}
|
||||||
|
short u1 = (short) (SCALE_FACTOR * x);
|
||||||
|
short v1 = (short) (SCALE_FACTOR * y);
|
||||||
|
short u2 = (short) (SCALE_FACTOR * (x + width));
|
||||||
|
short v2 = (short) (SCALE_FACTOR * (y + height));
|
||||||
|
|
||||||
|
short tx = (short) (SCALE_FACTOR * t.x);
|
||||||
|
short ty = (short) (SCALE_FACTOR * t.y);
|
||||||
|
// top-left
|
||||||
buf[pos++] = tx;
|
buf[pos++] = tx;
|
||||||
buf[pos++] = ty;
|
buf[pos++] = ty;
|
||||||
buf[pos++] = x1;
|
buf[pos++] = x1;
|
||||||
@ -273,23 +315,26 @@ public class TextRenderer {
|
|||||||
buf[pos++] = u1;
|
buf[pos++] = u1;
|
||||||
buf[pos++] = v2;
|
buf[pos++] = v2;
|
||||||
|
|
||||||
|
// top-right
|
||||||
buf[pos++] = tx;
|
buf[pos++] = tx;
|
||||||
buf[pos++] = ty;
|
buf[pos++] = ty;
|
||||||
buf[pos++] = x2;
|
buf[pos++] = x2;
|
||||||
buf[pos++] = y1;
|
buf[pos++] = y3;
|
||||||
buf[pos++] = u2;
|
buf[pos++] = u2;
|
||||||
buf[pos++] = v2;
|
buf[pos++] = v2;
|
||||||
|
|
||||||
|
// bot-right
|
||||||
buf[pos++] = tx;
|
buf[pos++] = tx;
|
||||||
buf[pos++] = ty;
|
buf[pos++] = ty;
|
||||||
buf[pos++] = x2;
|
buf[pos++] = x4;
|
||||||
buf[pos++] = y2;
|
buf[pos++] = y4;
|
||||||
buf[pos++] = u2;
|
buf[pos++] = u2;
|
||||||
buf[pos++] = v1;
|
buf[pos++] = v1;
|
||||||
|
|
||||||
|
// bot-left
|
||||||
buf[pos++] = tx;
|
buf[pos++] = tx;
|
||||||
buf[pos++] = ty;
|
buf[pos++] = ty;
|
||||||
buf[pos++] = x1;
|
buf[pos++] = x3;
|
||||||
buf[pos++] = y2;
|
buf[pos++] = y2;
|
||||||
buf[pos++] = u1;
|
buf[pos++] = u1;
|
||||||
buf[pos++] = v1;
|
buf[pos++] = v1;
|
||||||
@ -305,19 +350,16 @@ public class TextRenderer {
|
|||||||
tex.length = pos;
|
tex.length = pos;
|
||||||
tile.texture = tex;
|
tile.texture = tex;
|
||||||
tex.tile = tile;
|
tex.tile = tile;
|
||||||
// GlUtils.checkGlError("0");
|
|
||||||
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, tex.id);
|
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, tex.id);
|
||||||
// GlUtils.checkGlError("1");
|
GLUtils.texSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, mBitmap,
|
||||||
GLUtils.texSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, mBitmap, mBitmapFormat,
|
mBitmapFormat, mBitmapType);
|
||||||
mBitmapType);
|
|
||||||
// GlUtils.checkGlError("2");
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String TAG = "TextRenderer";
|
private static String TAG = "TextRenderer";
|
||||||
|
|
||||||
void compileTextures() {
|
static void compileTextures() {
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
TextTexture tex;
|
TextTexture tex;
|
||||||
|
|
||||||
@ -339,16 +381,18 @@ public class TextRenderer {
|
|||||||
// Log.d(TAG, "compileTextures" + mFloatBuffer.remaining() + " " + offset);
|
// Log.d(TAG, "compileTextures" + mFloatBuffer.remaining() + " " + offset);
|
||||||
|
|
||||||
// TODO use sub-bufferdata function
|
// TODO use sub-bufferdata function
|
||||||
GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, offset * (Short.SIZE / 8),
|
GLES20.glBufferSubData(GLES20.GL_ARRAY_BUFFER, 0, offset * (Short.SIZE / 8),
|
||||||
mShortBuffer, GLES20.GL_DYNAMIC_DRAW);
|
mShortBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void beginDraw(float scale) {
|
static void beginDraw(float scale) {
|
||||||
GLES20.glUseProgram(mTextProgram);
|
GLES20.glUseProgram(mTextProgram);
|
||||||
|
|
||||||
GLES20.glEnableVertexAttribArray(hTextTextureCoord);
|
GLES20.glEnableVertexAttribArray(hTextTextureCoord);
|
||||||
GLES20.glEnableVertexAttribArray(hTextVertex);
|
GLES20.glEnableVertexAttribArray(hTextVertex);
|
||||||
|
|
||||||
GLES20.glUniform1f(hTextScale, scale);
|
GLES20.glUniform1f(hTextScale, scale);
|
||||||
|
|
||||||
if (debug) {
|
if (debug) {
|
||||||
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
|
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
|
||||||
mShortBuffer.clear();
|
mShortBuffer.clear();
|
||||||
@ -365,13 +409,13 @@ public class TextRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void endDraw() {
|
static void endDraw() {
|
||||||
|
|
||||||
GLES20.glDisableVertexAttribArray(hTextTextureCoord);
|
GLES20.glDisableVertexAttribArray(hTextTextureCoord);
|
||||||
GLES20.glDisableVertexAttribArray(hTextVertex);
|
GLES20.glDisableVertexAttribArray(hTextVertex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawTile(GLMapTile tile, float[] matrix) {
|
static void drawTile(GLMapTile tile, float[] matrix) {
|
||||||
|
|
||||||
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, tile.texture.id);
|
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, tile.texture.id);
|
||||||
|
|
||||||
@ -384,43 +428,12 @@ public class TextRenderer {
|
|||||||
GLES20.glVertexAttribPointer(hTextVertex, 4,
|
GLES20.glVertexAttribPointer(hTextVertex, 4,
|
||||||
GLES20.GL_SHORT, false, 12, tile.texture.offset * (Short.SIZE / 8));
|
GLES20.GL_SHORT, false, 12, tile.texture.offset * (Short.SIZE / 8));
|
||||||
|
|
||||||
// GLES20.glVertexAttribPointer(hTextVertexOffset, 2,
|
|
||||||
// GLES20.GL_SHORT, false, 8, tile.texture.offset * (Short.SIZE / 8) + 4);
|
|
||||||
//
|
|
||||||
GLES20.glVertexAttribPointer(hTextTextureCoord, 2,
|
GLES20.glVertexAttribPointer(hTextTextureCoord, 2,
|
||||||
GLES20.GL_SHORT, false, 12, tile.texture.offset * (Short.SIZE / 8)
|
GLES20.GL_SHORT, false, 12, tile.texture.offset * (Short.SIZE / 8)
|
||||||
+ 8);
|
+ 8);
|
||||||
|
|
||||||
GLES20.glDrawElements(GLES20.GL_TRIANGLES, (tile.texture.length / 24) *
|
GLES20.glDrawElements(GLES20.GL_TRIANGLE_STRIP, (tile.texture.length / 24) *
|
||||||
INDICES_PER_SPRITE, GLES20.GL_UNSIGNED_SHORT, 0);
|
INDICES_PER_SPRITE, GLES20.GL_UNSIGNED_SHORT, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String textVertexShader = ""
|
|
||||||
+ "precision highp float; "
|
|
||||||
+ "attribute vec4 vertex;"
|
|
||||||
// + "attribute vec4 offset;"
|
|
||||||
+ "attribute vec2 tex_coord;"
|
|
||||||
+ "uniform mat4 mvp;"
|
|
||||||
+ "uniform float scale;"
|
|
||||||
+ "varying vec2 tex_c;"
|
|
||||||
+ "const vec2 div = vec2(1.0/1024.0,1.0/512.0);"
|
|
||||||
+ "const vec4 dp = vec4(0.5,0.5,0.5,0.5);"
|
|
||||||
+ "void main() {"
|
|
||||||
+ " vec4 s = dp * vertex;"
|
|
||||||
+ " gl_Position = mvp * vec4(s.x + (s.z / scale), s.y + (s.w / scale), 0.0, 1.0);"
|
|
||||||
// + " gl_Position = vec4(pos.x + s.z, pos.y + s.w, 0.0, 1.0);"
|
|
||||||
+ " tex_c = tex_coord * div;"
|
|
||||||
+ "}";
|
|
||||||
|
|
||||||
private static String textFragmentShader = ""
|
|
||||||
+ "precision highp float;"
|
|
||||||
+ "uniform sampler2D tex;"
|
|
||||||
+ "uniform vec4 col;"
|
|
||||||
+ "varying vec2 tex_c;"
|
|
||||||
+ "void main() {"
|
|
||||||
+ " gl_FragColor = texture2D(tex, tex_c.xy);"
|
|
||||||
+ "}";
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
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.content.Context;
|
||||||
import android.os.CountDownTimer;
|
import android.os.CountDownTimer;
|
||||||
import android.os.SystemClock;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.GestureDetector;
|
import android.view.GestureDetector;
|
||||||
import android.view.GestureDetector.SimpleOnGestureListener;
|
import android.view.GestureDetector.SimpleOnGestureListener;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.ScaleGestureDetector;
|
import android.view.ScaleGestureDetector;
|
||||||
import android.view.ViewConfiguration;
|
import android.view.ViewConfiguration;
|
||||||
import android.view.animation.DecelerateInterpolator;
|
|
||||||
import android.widget.Scroller;
|
import android.widget.Scroller;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -220,27 +218,15 @@ public class TouchHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// if (ret) {
|
// if (ret) {
|
||||||
// Log.d("", "" + );
|
// // throttle input
|
||||||
//
|
// long diff = SystemClock.uptimeMillis() - lastRun;
|
||||||
// // try {
|
// if (diff < 16 && diff > 5) {
|
||||||
// //
|
// // Log.d("", "" + diff);
|
||||||
// // Thread.sleep(10);
|
// SystemClock.sleep(16 - diff);
|
||||||
// // } catch (InterruptedException e) {
|
|
||||||
// // // TODO Auto-generated catch block
|
|
||||||
// // // e.printStackTrace();
|
|
||||||
// // }
|
|
||||||
//
|
|
||||||
// }
|
// }
|
||||||
if (ret) {
|
// lastRun = SystemClock.uptimeMillis();
|
||||||
// throttle input
|
// }
|
||||||
long diff = SystemClock.uptimeMillis() - lastRun;
|
|
||||||
if (diff < 16) {
|
|
||||||
// Log.d("", "" + diff);
|
|
||||||
SystemClock.sleep(16 - diff);
|
|
||||||
}
|
|
||||||
lastRun = SystemClock.uptimeMillis();
|
|
||||||
}
|
|
||||||
// the event was not handled
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,7 +236,8 @@ public class TouchHandler {
|
|||||||
private CountDownTimer mTimer = null;
|
private CountDownTimer mTimer = null;
|
||||||
|
|
||||||
public MapGestureDetector(MapView mapView) {
|
public MapGestureDetector(MapView mapView) {
|
||||||
mScroller = new Scroller(mapView.getContext(), new DecelerateInterpolator());
|
mScroller = new Scroller(mapView.getContext(),
|
||||||
|
new android.view.animation.LinearInterpolator());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -284,8 +271,8 @@ public class TouchHandler {
|
|||||||
@Override
|
@Override
|
||||||
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
|
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
|
||||||
float velocityY) {
|
float velocityY) {
|
||||||
int w = Tile.TILE_SIZE * 20;
|
int w = Tile.TILE_SIZE * 10;
|
||||||
int h = Tile.TILE_SIZE * 20;
|
int h = Tile.TILE_SIZE * 10;
|
||||||
mPrevX = 0;
|
mPrevX = 0;
|
||||||
mPrevY = 0;
|
mPrevY = 0;
|
||||||
|
|
||||||
@ -297,7 +284,7 @@ public class TouchHandler {
|
|||||||
mScroller.fling(0, 0, Math.round(velocityX) / 2, Math.round(velocityY) / 2,
|
mScroller.fling(0, 0, Math.round(velocityX) / 2, Math.round(velocityY) / 2,
|
||||||
-w, w, -h, h);
|
-w, w, -h, h);
|
||||||
// animate for two seconds
|
// animate for two seconds
|
||||||
mTimer = new CountDownTimer(2000, 20) {
|
mTimer = new CountDownTimer(2000, 40) {
|
||||||
@Override
|
@Override
|
||||||
public void onTick(long tick) {
|
public void onTick(long tick) {
|
||||||
if (!scroll())
|
if (!scroll())
|
||||||
|
|||||||
@ -46,14 +46,14 @@ public class JobQueue {
|
|||||||
* @param mapGeneratorJob
|
* @param mapGeneratorJob
|
||||||
* the job to be added to this queue.
|
* the job to be added to this queue.
|
||||||
*/
|
*/
|
||||||
public synchronized void addJob(MapGeneratorJob mapGeneratorJob) {
|
// public synchronized void addJob(MapGeneratorJob mapGeneratorJob) {
|
||||||
if (!mPriorityQueue.contains(mapGeneratorJob))
|
// if (!mPriorityQueue.contains(mapGeneratorJob))
|
||||||
// priorityQueue.remove(mapGeneratorJob);
|
// // priorityQueue.remove(mapGeneratorJob);
|
||||||
{
|
// {
|
||||||
mapGeneratorJob.tile.isLoading = true;
|
// //mapGeneratorJob.tile.isLoading = true;
|
||||||
mPriorityQueue.offer(mapGeneratorJob);
|
// mPriorityQueue.offer(mapGeneratorJob);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param jobs
|
* @param jobs
|
||||||
|
|||||||
@ -43,7 +43,7 @@ public class MapTile extends Tile {
|
|||||||
/**
|
/**
|
||||||
* distance from center, used in TileScheduler set by updateVisibleList.
|
* distance from center, used in TileScheduler set by updateVisibleList.
|
||||||
*/
|
*/
|
||||||
public long distance;
|
public float distance;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param tileX
|
* @param tileX
|
||||||
|
|||||||
@ -86,7 +86,7 @@ public class MapWorker extends PausableThread {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected int getThreadPriority() {
|
protected int getThreadPriority() {
|
||||||
return (Thread.NORM_PRIORITY + Thread.MIN_PRIORITY) / 2;
|
return (Thread.NORM_PRIORITY + Thread.MIN_PRIORITY) / 3;
|
||||||
// return mPrio;
|
// return mPrio;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -17,6 +17,7 @@ package org.mapsforge.android.rendertheme;
|
|||||||
import org.mapsforge.android.rendertheme.renderinstruction.Area;
|
import org.mapsforge.android.rendertheme.renderinstruction.Area;
|
||||||
import org.mapsforge.android.rendertheme.renderinstruction.Caption;
|
import org.mapsforge.android.rendertheme.renderinstruction.Caption;
|
||||||
import org.mapsforge.android.rendertheme.renderinstruction.Line;
|
import org.mapsforge.android.rendertheme.renderinstruction.Line;
|
||||||
|
import org.mapsforge.android.rendertheme.renderinstruction.PathText;
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
@ -31,7 +32,7 @@ public interface IRenderCallback {
|
|||||||
* @param area
|
* @param area
|
||||||
* ...
|
* ...
|
||||||
*/
|
*/
|
||||||
void renderArea(Area area);
|
void renderArea(Area area, int level);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders an area caption with the given text.
|
* Renders an area caption with the given text.
|
||||||
@ -83,7 +84,7 @@ public interface IRenderCallback {
|
|||||||
* @param line
|
* @param line
|
||||||
* ...
|
* ...
|
||||||
*/
|
*/
|
||||||
void renderWay(Line line);
|
void renderWay(Line line, int level);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders a way with the given symbol along the way path.
|
* Renders a way with the given symbol along the way path.
|
||||||
@ -100,12 +101,8 @@ public interface IRenderCallback {
|
|||||||
/**
|
/**
|
||||||
* Renders a way with the given text along the way path.
|
* Renders a way with the given text along the way path.
|
||||||
*
|
*
|
||||||
* @param text
|
* @param pathText
|
||||||
* the text to be rendered.
|
* ...
|
||||||
* @param paint
|
|
||||||
* the paint to be used for rendering the text.
|
|
||||||
* @param stroke
|
|
||||||
* an optional paint for the text casing (may be null).
|
|
||||||
*/
|
*/
|
||||||
void renderWayText(String text, Paint paint, Paint stroke);
|
void renderWayText(PathText pathText);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,8 +21,9 @@ import org.mapsforge.core.Tag;
|
|||||||
class NegativeMatcher implements AttributeMatcher {
|
class NegativeMatcher implements AttributeMatcher {
|
||||||
private final String[] mKeyList;
|
private final String[] mKeyList;
|
||||||
private final String[] mValueList;
|
private final String[] mValueList;
|
||||||
|
private final boolean mExclusive;
|
||||||
|
|
||||||
NegativeMatcher(List<String> keyList, List<String> valueList) {
|
NegativeMatcher(List<String> keyList, List<String> valueList, boolean exclusive) {
|
||||||
mKeyList = new String[keyList.size()];
|
mKeyList = new String[keyList.size()];
|
||||||
for (int i = 0; i < mKeyList.length; i++)
|
for (int i = 0; i < mKeyList.length; i++)
|
||||||
mKeyList[i] = keyList.get(i).intern();
|
mKeyList[i] = keyList.get(i).intern();
|
||||||
@ -30,6 +31,8 @@ class NegativeMatcher implements AttributeMatcher {
|
|||||||
mValueList = new String[valueList.size()];
|
mValueList = new String[valueList.size()];
|
||||||
for (int i = 0; i < mValueList.length; i++)
|
for (int i = 0; i < mValueList.length; i++)
|
||||||
mValueList[i] = valueList.get(i).intern();
|
mValueList[i] = valueList.get(i).intern();
|
||||||
|
|
||||||
|
mExclusive = exclusive;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -46,9 +49,9 @@ class NegativeMatcher implements AttributeMatcher {
|
|||||||
for (Tag tag : tags) {
|
for (Tag tag : tags) {
|
||||||
for (String value : mValueList)
|
for (String value : mValueList)
|
||||||
if (value == tag.value)
|
if (value == tag.value)
|
||||||
return true;
|
return !mExclusive;
|
||||||
}
|
}
|
||||||
return false;
|
return mExclusive;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean keyListDoesNotContainKeys(Tag[] tags) {
|
private boolean keyListDoesNotContainKeys(Tag[] tags) {
|
||||||
|
|||||||
@ -29,14 +29,14 @@ class NegativeRule extends Rule {
|
|||||||
@Override
|
@Override
|
||||||
boolean matchesNode(Tag[] tags, byte zoomLevel) {
|
boolean matchesNode(Tag[] tags, byte zoomLevel) {
|
||||||
return mZoomMin <= zoomLevel && mZoomMax >= zoomLevel
|
return mZoomMin <= zoomLevel && mZoomMax >= zoomLevel
|
||||||
&& (mElement == Element.NODE || mElement == Element.ANY)
|
&& (mElement != Element.WAY)
|
||||||
&& mAttributeMatcher.matches(tags);
|
&& mAttributeMatcher.matches(tags);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
boolean matchesWay(Tag[] tags, byte zoomLevel, int closed) {
|
boolean matchesWay(Tag[] tags, byte zoomLevel, int closed) {
|
||||||
return mZoomMin <= zoomLevel && mZoomMax >= zoomLevel
|
return mZoomMin <= zoomLevel && mZoomMax >= zoomLevel
|
||||||
&& (mElement == Element.WAY || mElement == Element.ANY)
|
&& (mElement != Element.NODE)
|
||||||
&& (mClosed == closed || mClosed == Closed.ANY)
|
&& (mClosed == closed || mClosed == Closed.ANY)
|
||||||
&& mAttributeMatcher.matches(tags);
|
&& mAttributeMatcher.matches(tags);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,16 +37,16 @@ class PositiveRule extends Rule {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
boolean matchesNode(Tag[] tags, byte zoomLevel) {
|
boolean matchesNode(Tag[] tags, byte zoomLevel) {
|
||||||
return mZoomMin <= zoomLevel && mZoomMax >= zoomLevel
|
return (mElement != Element.WAY)
|
||||||
&& (mElement == Element.NODE || mElement == Element.ANY)
|
&& mZoomMin <= zoomLevel && mZoomMax >= zoomLevel
|
||||||
&& (mKeyMatcher == null || mKeyMatcher.matches(tags))
|
&& (mKeyMatcher == null || mKeyMatcher.matches(tags))
|
||||||
&& (mValueMatcher == null || mValueMatcher.matches(tags));
|
&& (mValueMatcher == null || mValueMatcher.matches(tags));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
boolean matchesWay(Tag[] tags, byte zoomLevel, int closed) {
|
boolean matchesWay(Tag[] tags, byte zoomLevel, int closed) {
|
||||||
return mZoomMin <= zoomLevel && mZoomMax >= zoomLevel
|
return (mElement != Element.NODE)
|
||||||
&& (mElement == Element.WAY || mElement == Element.ANY)
|
&& mZoomMin <= zoomLevel && mZoomMax >= zoomLevel
|
||||||
&& (mClosed == closed || mClosed == Closed.ANY)
|
&& (mClosed == closed || mClosed == Closed.ANY)
|
||||||
&& (mKeyMatcher == null || mKeyMatcher.matches(tags))
|
&& (mKeyMatcher == null || mKeyMatcher.matches(tags))
|
||||||
&& (mValueMatcher == null || mValueMatcher.matches(tags));
|
&& (mValueMatcher == null || mValueMatcher.matches(tags));
|
||||||
|
|||||||
@ -17,7 +17,6 @@ package org.mapsforge.android.rendertheme;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.mapsforge.android.rendertheme.renderinstruction.Line;
|
|
||||||
import org.mapsforge.android.rendertheme.renderinstruction.RenderInstruction;
|
import org.mapsforge.android.rendertheme.renderinstruction.RenderInstruction;
|
||||||
import org.mapsforge.core.LRUCache;
|
import org.mapsforge.core.LRUCache;
|
||||||
import org.mapsforge.core.Tag;
|
import org.mapsforge.core.Tag;
|
||||||
@ -136,40 +135,112 @@ public class RenderTheme {
|
|||||||
* ...
|
* ...
|
||||||
* @param zoomLevel
|
* @param zoomLevel
|
||||||
* ...
|
* ...
|
||||||
|
* @return ...
|
||||||
*/
|
*/
|
||||||
public void matchNode(IRenderCallback renderCallback, Tag[] tags, byte zoomLevel) {
|
public synchronized RenderInstruction[] matchNode(IRenderCallback renderCallback,
|
||||||
// List<RenderInstruction> matchingList = matchingListNode;
|
Tag[] tags,
|
||||||
// MatchingCacheKey matchingCacheKey = matchingCacheKeyNode;
|
byte zoomLevel) {
|
||||||
|
|
||||||
// if (!changed) {
|
RenderInstruction[] renderInstructions = null;
|
||||||
// if (matchingList != null) {
|
|
||||||
// for (int i = 0, n = matchingList.size(); i < n; ++i) {
|
|
||||||
// matchingList.get(i).renderNode(renderCallback, tags);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// matchingCacheKey = new MatchingCacheKey(tags, zoomLevel);
|
|
||||||
// matchingList = matchingCacheNodes.get(matchingCacheKey);
|
|
||||||
//
|
|
||||||
// if (matchingList != null) {
|
|
||||||
// // cache hit
|
|
||||||
// for (int i = 0, n = matchingList.size(); i < n; ++i) {
|
|
||||||
// matchingList.get(i).renderNode(renderCallback, tags);
|
|
||||||
// }
|
|
||||||
// } else {
|
|
||||||
|
|
||||||
// cache miss
|
MatchingCacheKey matchingCacheKey;
|
||||||
// matchingList = new ArrayList<RenderInstruction>();
|
|
||||||
for (int i = 0, n = mRulesList.size(); i < n; ++i) {
|
matchingCacheKey = new MatchingCacheKey(tags, zoomLevel);
|
||||||
mRulesList.get(i).matchNode(renderCallback, tags, zoomLevel);
|
boolean found = mMatchingCacheNodes.containsKey(matchingCacheKey);
|
||||||
// , matchingList
|
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);
|
|
||||||
// }
|
if (renderInstructions != null) {
|
||||||
//
|
for (int i = 0, n = renderInstructions.length; i < n; i++)
|
||||||
// matchingListNode = matchingList;
|
renderInstructions[i].renderNode(renderCallback, tags);
|
||||||
// matchingCacheKeyNode = matchingCacheKey;
|
}
|
||||||
|
|
||||||
|
return renderInstructions;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches a way with the given parameters against this RenderTheme.
|
||||||
|
*
|
||||||
|
* @param renderCallback
|
||||||
|
* the callback implementation which will be executed on each match.
|
||||||
|
* @param tags
|
||||||
|
* the tags of the way.
|
||||||
|
* @param zoomLevel
|
||||||
|
* the zoom level at which the way should be matched.
|
||||||
|
* @param closed
|
||||||
|
* way is Closed
|
||||||
|
* @param render
|
||||||
|
* ...
|
||||||
|
* @return currently processed render instructions
|
||||||
|
*/
|
||||||
|
public synchronized RenderInstruction[] matchWay(IRenderCallback renderCallback,
|
||||||
|
Tag[] tags,
|
||||||
|
byte zoomLevel,
|
||||||
|
boolean closed, boolean render) {
|
||||||
|
RenderInstruction[] renderInstructions = null;
|
||||||
|
|
||||||
|
LRUCache<MatchingCacheKey, RenderInstruction[]> matchingCache;
|
||||||
|
MatchingCacheKey matchingCacheKey;
|
||||||
|
|
||||||
|
if (closed) {
|
||||||
|
matchingCache = mMatchingCacheArea;
|
||||||
|
} else {
|
||||||
|
matchingCache = mMatchingCacheWay;
|
||||||
|
}
|
||||||
|
|
||||||
|
matchingCacheKey = new MatchingCacheKey(tags, zoomLevel);
|
||||||
|
boolean found = matchingCache.containsKey(matchingCacheKey);
|
||||||
|
if (found) {
|
||||||
|
renderInstructions = matchingCache.get(matchingCacheKey);
|
||||||
|
} else {
|
||||||
|
// cache miss
|
||||||
|
int c = (closed ? Closed.YES : Closed.NO);
|
||||||
|
List<RenderInstruction> matchingList = new ArrayList<RenderInstruction>(4);
|
||||||
|
for (int i = 0, n = mRulesList.size(); i < n; ++i) {
|
||||||
|
mRulesList.get(i).matchWay(renderCallback, tags, zoomLevel, c,
|
||||||
|
matchingList);
|
||||||
|
}
|
||||||
|
int size = matchingList.size();
|
||||||
|
if (size > 0) {
|
||||||
|
renderInstructions = new RenderInstruction[size];
|
||||||
|
matchingList.toArray(renderInstructions);
|
||||||
|
}
|
||||||
|
matchingCache.put(matchingCacheKey, renderInstructions);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (render && renderInstructions != null) {
|
||||||
|
for (int i = 0, n = renderInstructions.length; i < n; i++)
|
||||||
|
renderInstructions[i].renderWay(renderCallback, tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
return renderInstructions;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addRule(Rule rule) {
|
||||||
|
mRulesList.add(rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
void complete() {
|
||||||
|
mRulesList.trimToSize();
|
||||||
|
for (int i = 0, n = mRulesList.size(); i < n; ++i) {
|
||||||
|
mRulesList.get(i).onComplete();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -196,107 +267,6 @@ public class RenderTheme {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// private RenderInstruction[] mRenderInstructions = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Matches a way with the given parameters against this RenderTheme.
|
|
||||||
*
|
|
||||||
* @param renderCallback
|
|
||||||
* the callback implementation which will be executed on each match.
|
|
||||||
* @param tags
|
|
||||||
* the tags of the way.
|
|
||||||
* @param zoomLevel
|
|
||||||
* the zoom level at which the way should be matched.
|
|
||||||
* @param closed
|
|
||||||
* way is Closed
|
|
||||||
* @param changed
|
|
||||||
* ...
|
|
||||||
* @return currently processed render instructions
|
|
||||||
*/
|
|
||||||
public synchronized RenderInstruction[] matchWay(IRenderCallback renderCallback,
|
|
||||||
Tag[] tags,
|
|
||||||
byte zoomLevel,
|
|
||||||
boolean closed, boolean render) {
|
|
||||||
RenderInstruction[] renderInstructions = null;
|
|
||||||
|
|
||||||
LRUCache<MatchingCacheKey, RenderInstruction[]> matchingCache;
|
|
||||||
MatchingCacheKey matchingCacheKey;
|
|
||||||
|
|
||||||
// if (!changed) {
|
|
||||||
// renderInstructions = mRenderInstructions;
|
|
||||||
//
|
|
||||||
// if (renderInstructions != null) {
|
|
||||||
// for (int i = 0, n = renderInstructions.length; i < n; i++)
|
|
||||||
// renderInstructions[i].renderWay(renderCallback, tags);
|
|
||||||
// }
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (closed) {
|
|
||||||
matchingCache = mMatchingCacheArea;
|
|
||||||
} else {
|
|
||||||
matchingCache = mMatchingCacheWay;
|
|
||||||
}
|
|
||||||
|
|
||||||
matchingCacheKey = new MatchingCacheKey(tags, zoomLevel);
|
|
||||||
boolean found = matchingCache.containsKey(matchingCacheKey);
|
|
||||||
if (found) {
|
|
||||||
renderInstructions = matchingCache.get(matchingCacheKey);
|
|
||||||
} else {
|
|
||||||
// cache miss
|
|
||||||
int c = (closed ? Closed.YES : Closed.NO);
|
|
||||||
List<RenderInstruction> matchingList = new ArrayList<RenderInstruction>(4);
|
|
||||||
for (int i = 0, n = mRulesList.size(); i < n; ++i) {
|
|
||||||
mRulesList.get(i).matchWay(renderCallback, tags, zoomLevel, c,
|
|
||||||
matchingList);
|
|
||||||
}
|
|
||||||
int size = matchingList.size();
|
|
||||||
if (size > 0) {
|
|
||||||
renderInstructions = new RenderInstruction[matchingList.size()];
|
|
||||||
for (int i = 0, n = matchingList.size(); i < n; ++i) {
|
|
||||||
RenderInstruction renderInstruction = matchingList.get(i);
|
|
||||||
|
|
||||||
renderInstructions[i] = renderInstruction;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
matchingCache.put(matchingCacheKey, renderInstructions);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (render && renderInstructions != null) {
|
|
||||||
for (int i = 0, n = renderInstructions.length; i < n; i++)
|
|
||||||
renderInstructions[i].renderWay(renderCallback, tags);
|
|
||||||
}
|
|
||||||
// mRenderInstructions = renderInstructions;
|
|
||||||
return renderInstructions;
|
|
||||||
}
|
|
||||||
|
|
||||||
void addRule(Rule rule) {
|
|
||||||
mRulesList.add(rule);
|
|
||||||
}
|
|
||||||
|
|
||||||
void complete() {
|
|
||||||
mRulesList.trimToSize();
|
|
||||||
for (int i = 0, n = mRulesList.size(); i < n; ++i) {
|
|
||||||
mRulesList.get(i).onComplete();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private final ArrayList<Line> outlineLayers = new ArrayList<Line>();
|
|
||||||
|
|
||||||
void addOutlineLayer(Line line) {
|
|
||||||
outlineLayers.add(line);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param layer
|
|
||||||
* ...
|
|
||||||
* @return Line (paint and level) used for outline
|
|
||||||
*/
|
|
||||||
public Line getOutline(int layer) {
|
|
||||||
return outlineLayers.get(layer);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setLevels(int levels) {
|
void setLevels(int levels) {
|
||||||
mLevels = levels;
|
mLevels = levels;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,6 +16,7 @@ package org.mapsforge.android.rendertheme;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Stack;
|
import java.util.Stack;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
@ -26,9 +27,11 @@ import javax.xml.parsers.SAXParserFactory;
|
|||||||
import org.mapsforge.android.rendertheme.renderinstruction.Area;
|
import org.mapsforge.android.rendertheme.renderinstruction.Area;
|
||||||
import org.mapsforge.android.rendertheme.renderinstruction.Caption;
|
import org.mapsforge.android.rendertheme.renderinstruction.Caption;
|
||||||
import org.mapsforge.android.rendertheme.renderinstruction.Circle;
|
import org.mapsforge.android.rendertheme.renderinstruction.Circle;
|
||||||
|
import org.mapsforge.android.rendertheme.renderinstruction.AreaLevel;
|
||||||
import org.mapsforge.android.rendertheme.renderinstruction.Line;
|
import org.mapsforge.android.rendertheme.renderinstruction.Line;
|
||||||
import org.mapsforge.android.rendertheme.renderinstruction.LineSymbol;
|
import org.mapsforge.android.rendertheme.renderinstruction.LineSymbol;
|
||||||
import org.mapsforge.android.rendertheme.renderinstruction.PathText;
|
import org.mapsforge.android.rendertheme.renderinstruction.PathText;
|
||||||
|
import org.mapsforge.android.rendertheme.renderinstruction.RenderInstruction;
|
||||||
import org.mapsforge.android.rendertheme.renderinstruction.Symbol;
|
import org.mapsforge.android.rendertheme.renderinstruction.Symbol;
|
||||||
import org.xml.sax.Attributes;
|
import org.xml.sax.Attributes;
|
||||||
import org.xml.sax.InputSource;
|
import org.xml.sax.InputSource;
|
||||||
@ -41,14 +44,23 @@ import org.xml.sax.helpers.DefaultHandler;
|
|||||||
* SAX2 handler to parse XML render theme files.
|
* SAX2 handler to parse XML render theme files.
|
||||||
*/
|
*/
|
||||||
public class RenderThemeHandler extends DefaultHandler {
|
public class RenderThemeHandler extends DefaultHandler {
|
||||||
private static final Logger LOG = Logger.getLogger(RenderThemeHandler.class.getName());
|
private static final Logger LOG = Logger
|
||||||
|
.getLogger(RenderThemeHandler.class.getName());
|
||||||
|
|
||||||
private static enum Element {
|
private static enum Element {
|
||||||
RENDER_THEME, RENDERING_INSTRUCTION, RULE;
|
RENDER_THEME, RENDERING_INSTRUCTION, RULE, STYLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final String ELEMENT_NAME_RENDER_THEME = "rendertheme";
|
private static final String ELEMENT_NAME_RENDER_THEME = "rendertheme";
|
||||||
private static final String ELEMENT_NAME_RULE = "rule";
|
private static final String ELEMENT_NAME_RULE = "rule";
|
||||||
|
private static final String ELEMENT_NAME_STYPE_PATH_TEXT = "style-pathtext";
|
||||||
|
private static final String ELEMENT_NAME_STYLE_AREA = "style-area";
|
||||||
|
private static final String ELEMENT_NAME_STYLE_LINE = "style-line";
|
||||||
|
private static final String ELEMENT_NAME_STYLE_OUTLINE = "style-outline";
|
||||||
|
private static final String ELEMENT_NAME_USE_STYLE_PATH_TEXT = "use-text";
|
||||||
|
private static final String ELEMENT_NAME_USE_STYLE_AREA = "use-area";
|
||||||
|
private static final String ELEMENT_NAME_USE_STYLE_LINE = "use-line";
|
||||||
|
private static final String ELEMENT_NAME_USE_STYLE_OUTLINE = "use-outline";
|
||||||
private static final String UNEXPECTED_ELEMENT = "unexpected element: ";
|
private static final String UNEXPECTED_ELEMENT = "unexpected element: ";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -62,10 +74,12 @@ public class RenderThemeHandler extends DefaultHandler {
|
|||||||
* @throws IOException
|
* @throws IOException
|
||||||
* if an I/O error occurs while reading from the input stream.
|
* if an I/O error occurs while reading from the input stream.
|
||||||
*/
|
*/
|
||||||
public static RenderTheme getRenderTheme(InputStream inputStream) throws SAXException,
|
public static RenderTheme getRenderTheme(InputStream inputStream)
|
||||||
|
throws SAXException,
|
||||||
ParserConfigurationException, IOException {
|
ParserConfigurationException, IOException {
|
||||||
RenderThemeHandler renderThemeHandler = new RenderThemeHandler();
|
RenderThemeHandler renderThemeHandler = new RenderThemeHandler();
|
||||||
XMLReader xmlReader = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
|
XMLReader xmlReader = SAXParserFactory.newInstance().newSAXParser()
|
||||||
|
.getXMLReader();
|
||||||
xmlReader.setContentHandler(renderThemeHandler);
|
xmlReader.setContentHandler(renderThemeHandler);
|
||||||
xmlReader.parse(new InputSource(inputStream));
|
xmlReader.parse(new InputSource(inputStream));
|
||||||
return renderThemeHandler.mRenderTheme;
|
return renderThemeHandler.mRenderTheme;
|
||||||
@ -83,7 +97,8 @@ public class RenderThemeHandler extends DefaultHandler {
|
|||||||
* @param attributeIndex
|
* @param attributeIndex
|
||||||
* the XML attribute index position.
|
* the XML attribute index position.
|
||||||
*/
|
*/
|
||||||
public static void logUnknownAttribute(String element, String name, String value, int attributeIndex) {
|
public static void logUnknownAttribute(String element, String name, String value,
|
||||||
|
int attributeIndex) {
|
||||||
StringBuilder stringBuilder = new StringBuilder();
|
StringBuilder stringBuilder = new StringBuilder();
|
||||||
stringBuilder.append("unknown attribute in element ");
|
stringBuilder.append("unknown attribute in element ");
|
||||||
stringBuilder.append(element);
|
stringBuilder.append(element);
|
||||||
@ -110,6 +125,7 @@ public class RenderThemeHandler extends DefaultHandler {
|
|||||||
|
|
||||||
mRenderTheme.setLevels(mLevel);
|
mRenderTheme.setLevels(mLevel);
|
||||||
mRenderTheme.complete();
|
mRenderTheme.complete();
|
||||||
|
tmpStyleHash.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -131,8 +147,12 @@ public class RenderThemeHandler extends DefaultHandler {
|
|||||||
LOG.log(Level.SEVERE, null, exception);
|
LOG.log(Level.SEVERE, null, exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static HashMap<String, RenderInstruction> tmpStyleHash = new HashMap<String, RenderInstruction>(
|
||||||
|
10);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
|
public void startElement(String uri, String localName, String qName,
|
||||||
|
Attributes attributes) throws SAXException {
|
||||||
try {
|
try {
|
||||||
if (ELEMENT_NAME_RENDER_THEME.equals(localName)) {
|
if (ELEMENT_NAME_RENDER_THEME.equals(localName)) {
|
||||||
checkState(localName, Element.RENDER_THEME);
|
checkState(localName, Element.RENDER_THEME);
|
||||||
@ -149,10 +169,53 @@ public class RenderThemeHandler extends DefaultHandler {
|
|||||||
mRuleStack.push(mCurrentRule);
|
mRuleStack.push(mCurrentRule);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
else if (ELEMENT_NAME_STYPE_PATH_TEXT.equals(localName)) {
|
||||||
|
checkState(localName, Element.STYLE);
|
||||||
|
PathText pathText = PathText.create(localName, attributes);
|
||||||
|
tmpStyleHash.put("t" + pathText.style, pathText);
|
||||||
|
// System.out.println("add style: " + pathText.style);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (ELEMENT_NAME_STYLE_AREA.equals(localName)) {
|
||||||
|
checkState(localName, Element.STYLE);
|
||||||
|
Area area = Area.create(localName, attributes, 0);
|
||||||
|
tmpStyleHash.put("a" + area.style, area);
|
||||||
|
// System.out.println("add style: " + area.style);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (ELEMENT_NAME_STYLE_LINE.equals(localName)) {
|
||||||
|
checkState(localName, Element.STYLE);
|
||||||
|
String style = null;
|
||||||
|
if ((style = attributes.getValue("from")) != null) {
|
||||||
|
RenderInstruction ri = tmpStyleHash.get("l" + style);
|
||||||
|
if (ri instanceof Line) {
|
||||||
|
Line line = Line.create((Line) ri, localName, attributes, 0,
|
||||||
|
false);
|
||||||
|
tmpStyleHash.put("l" + line.style, line);
|
||||||
|
// System.out.println("add style: " + line.style + " from " + style);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// System.out.println("couldnt check the style yo! " + style);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Line line = Line.create(null, localName, attributes, 0, false);
|
||||||
|
tmpStyleHash.put("l" + line.style, line);
|
||||||
|
// System.out.println("add style: " + line.style);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (ELEMENT_NAME_STYLE_OUTLINE.equals(localName)) {
|
||||||
|
checkState(localName, Element.RENDERING_INSTRUCTION);
|
||||||
|
Line line = Line.create(null, localName, attributes, mLevel++, true);
|
||||||
|
tmpStyleHash.put("o" + line.style, line);
|
||||||
|
// outlineLayers.add(line);
|
||||||
|
}
|
||||||
|
|
||||||
else if ("area".equals(localName)) {
|
else if ("area".equals(localName)) {
|
||||||
checkState(localName, Element.RENDERING_INSTRUCTION);
|
checkState(localName, Element.RENDERING_INSTRUCTION);
|
||||||
Area area = Area.create(localName, attributes, mLevel++);
|
Area area = Area.create(localName, attributes, mLevel++);
|
||||||
mRuleStack.peek().addRenderingInstruction(area);
|
// mRuleStack.peek().addRenderingInstruction(area);
|
||||||
|
mCurrentRule.addRenderingInstruction(area);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if ("caption".equals(localName)) {
|
else if ("caption".equals(localName)) {
|
||||||
@ -169,17 +232,10 @@ public class RenderThemeHandler extends DefaultHandler {
|
|||||||
|
|
||||||
else if ("line".equals(localName)) {
|
else if ("line".equals(localName)) {
|
||||||
checkState(localName, Element.RENDERING_INSTRUCTION);
|
checkState(localName, Element.RENDERING_INSTRUCTION);
|
||||||
Line line = Line.create(localName, attributes, mLevel++);
|
Line line = Line.create(null, localName, attributes, mLevel++, false);
|
||||||
mCurrentRule.addRenderingInstruction(line);
|
mCurrentRule.addRenderingInstruction(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if ("outline".equals(localName)) {
|
|
||||||
checkState(localName, Element.RENDERING_INSTRUCTION);
|
|
||||||
Line line = Line.create(localName, attributes, mLevel++);
|
|
||||||
mRenderTheme.addOutlineLayer(line);
|
|
||||||
// mCurrentRule.addRenderingInstruction(line);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if ("lineSymbol".equals(localName)) {
|
else if ("lineSymbol".equals(localName)) {
|
||||||
checkState(localName, Element.RENDERING_INSTRUCTION);
|
checkState(localName, Element.RENDERING_INSTRUCTION);
|
||||||
LineSymbol lineSymbol = LineSymbol.create(localName, attributes);
|
LineSymbol lineSymbol = LineSymbol.create(localName, attributes);
|
||||||
@ -198,7 +254,45 @@ public class RenderThemeHandler extends DefaultHandler {
|
|||||||
mCurrentRule.addRenderingInstruction(symbol);
|
mCurrentRule.addRenderingInstruction(symbol);
|
||||||
}
|
}
|
||||||
|
|
||||||
else {
|
else if (ELEMENT_NAME_USE_STYLE_LINE.equals(localName)) {
|
||||||
|
checkState(localName, Element.RENDERING_INSTRUCTION);
|
||||||
|
String style = attributes.getValue("name");
|
||||||
|
if (style != null) {
|
||||||
|
Line line = (Line) tmpStyleHash.get("l" + style);
|
||||||
|
if (line != null) {
|
||||||
|
// System.out.println("found style line : " + line.style);
|
||||||
|
Line newLine = Line.create(line, localName, attributes,
|
||||||
|
mLevel++, false);
|
||||||
|
|
||||||
|
mCurrentRule.addRenderingInstruction(newLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (ELEMENT_NAME_USE_STYLE_OUTLINE.equals(localName)) {
|
||||||
|
checkState(localName, Element.RENDERING_INSTRUCTION);
|
||||||
|
String style = attributes.getValue("name");
|
||||||
|
if (style != null) {
|
||||||
|
Line line = (Line) tmpStyleHash.get("o" + style);
|
||||||
|
if (line != null && line.outline)
|
||||||
|
mCurrentRule.addRenderingInstruction(line);
|
||||||
|
}
|
||||||
|
} else if (ELEMENT_NAME_USE_STYLE_AREA.equals(localName)) {
|
||||||
|
checkState(localName, Element.RENDERING_INSTRUCTION);
|
||||||
|
String style = attributes.getValue("name");
|
||||||
|
if (style != null) {
|
||||||
|
Area area = (Area) tmpStyleHash.get("a" + style);
|
||||||
|
if (area != null)
|
||||||
|
mCurrentRule.addRenderingInstruction(new AreaLevel(area,
|
||||||
|
mLevel++));
|
||||||
|
}
|
||||||
|
} else if (ELEMENT_NAME_USE_STYLE_PATH_TEXT.equals(localName)) {
|
||||||
|
checkState(localName, Element.RENDERING_INSTRUCTION);
|
||||||
|
String style = attributes.getValue("name");
|
||||||
|
if (style != null) {
|
||||||
|
PathText pt = (PathText) tmpStyleHash.get("t" + style);
|
||||||
|
if (pt != null)
|
||||||
|
mCurrentRule.addRenderingInstruction(pt);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
throw new SAXException("unknown element: " + localName);
|
throw new SAXException("unknown element: " + localName);
|
||||||
}
|
}
|
||||||
} catch (IllegalArgumentException e) {
|
} catch (IllegalArgumentException e) {
|
||||||
@ -214,6 +308,7 @@ public class RenderThemeHandler extends DefaultHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void checkElement(String elementName, Element element) throws SAXException {
|
private void checkElement(String elementName, Element element) throws SAXException {
|
||||||
|
Element parentElement;
|
||||||
switch (element) {
|
switch (element) {
|
||||||
case RENDER_THEME:
|
case RENDER_THEME:
|
||||||
if (!mElementStack.empty()) {
|
if (!mElementStack.empty()) {
|
||||||
@ -222,8 +317,16 @@ public class RenderThemeHandler extends DefaultHandler {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
case RULE:
|
case RULE:
|
||||||
Element parentElement = mElementStack.peek();
|
parentElement = mElementStack.peek();
|
||||||
if (parentElement != Element.RENDER_THEME && parentElement != Element.RULE) {
|
if (parentElement != Element.RENDER_THEME
|
||||||
|
&& parentElement != Element.RULE) {
|
||||||
|
throw new SAXException(UNEXPECTED_ELEMENT + elementName);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
case STYLE:
|
||||||
|
parentElement = mElementStack.peek();
|
||||||
|
if (parentElement != Element.RENDER_THEME) {
|
||||||
throw new SAXException(UNEXPECTED_ELEMENT + elementName);
|
throw new SAXException(UNEXPECTED_ELEMENT + elementName);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -32,6 +32,7 @@ abstract class Rule {
|
|||||||
private static final Map<List<String>, AttributeMatcher> MATCHERS_CACHE_VALUE = new HashMap<List<String>, AttributeMatcher>();
|
private static final Map<List<String>, AttributeMatcher> MATCHERS_CACHE_VALUE = new HashMap<List<String>, AttributeMatcher>();
|
||||||
private static final Pattern SPLIT_PATTERN = Pattern.compile("\\|");
|
private static final Pattern SPLIT_PATTERN = Pattern.compile("\\|");
|
||||||
private static final String STRING_NEGATION = "~";
|
private static final String STRING_NEGATION = "~";
|
||||||
|
private static final String STRING_EXCLUSIVE = "-";
|
||||||
private static final String STRING_WILDCARD = "*";
|
private static final String STRING_WILDCARD = "*";
|
||||||
|
|
||||||
private static Rule createRule(Stack<Rule> ruleStack, int element, String keys,
|
private static Rule createRule(Stack<Rule> ruleStack, int element, String keys,
|
||||||
@ -44,11 +45,18 @@ abstract class Rule {
|
|||||||
.split(values)));
|
.split(values)));
|
||||||
|
|
||||||
if (valueList.remove(STRING_NEGATION)) {
|
if (valueList.remove(STRING_NEGATION)) {
|
||||||
AttributeMatcher attributeMatcher = new NegativeMatcher(keyList, valueList);
|
AttributeMatcher attributeMatcher = new NegativeMatcher(keyList, valueList,
|
||||||
|
false);
|
||||||
return new NegativeRule(element, closed, zoomMin, zoomMax,
|
return new NegativeRule(element, closed, zoomMin, zoomMax,
|
||||||
attributeMatcher);
|
attributeMatcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (valueList.remove(STRING_EXCLUSIVE)) {
|
||||||
|
AttributeMatcher attributeMatcher = new NegativeMatcher(keyList, valueList,
|
||||||
|
true);
|
||||||
|
return new NegativeRule(element, closed, zoomMin, zoomMax,
|
||||||
|
attributeMatcher);
|
||||||
|
}
|
||||||
AttributeMatcher keyMatcher = getKeyMatcher(keyList);
|
AttributeMatcher keyMatcher = getKeyMatcher(keyList);
|
||||||
AttributeMatcher valueMatcher = getValueMatcher(valueList);
|
AttributeMatcher valueMatcher = getValueMatcher(valueList);
|
||||||
|
|
||||||
@ -189,13 +197,14 @@ abstract class Rule {
|
|||||||
|
|
||||||
abstract boolean matchesWay(Tag[] tags, byte zoomLevel, int closed);
|
abstract boolean matchesWay(Tag[] tags, byte zoomLevel, int closed);
|
||||||
|
|
||||||
void matchNode(IRenderCallback renderCallback, Tag[] tags, byte zoomLevel) {
|
void matchNode(IRenderCallback renderCallback, Tag[] tags, byte zoomLevel,
|
||||||
|
List<RenderInstruction> matchingList) {
|
||||||
if (matchesNode(tags, zoomLevel)) {
|
if (matchesNode(tags, zoomLevel)) {
|
||||||
for (int i = 0, n = mRenderInstructionArray.length; i < n; i++)
|
for (int i = 0, n = mRenderInstructionArray.length; i < n; i++)
|
||||||
mRenderInstructionArray[i].renderNode(renderCallback, tags);
|
matchingList.add(mRenderInstructionArray[i]);
|
||||||
|
|
||||||
for (int i = 0, n = mSubRuleArray.length; i < n; i++)
|
for (int i = 0, n = mSubRuleArray.length; i < n; i++)
|
||||||
mSubRuleArray[i].matchNode(renderCallback, tags, zoomLevel);
|
mSubRuleArray[i].matchNode(renderCallback, tags, zoomLevel, matchingList);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -220,14 +229,15 @@ abstract class Rule {
|
|||||||
MATCHERS_CACHE_VALUE.clear();
|
MATCHERS_CACHE_VALUE.clear();
|
||||||
|
|
||||||
mRenderInstructionArray = new RenderInstruction[mRenderInstructions.size()];
|
mRenderInstructionArray = new RenderInstruction[mRenderInstructions.size()];
|
||||||
|
mRenderInstructions.toArray(mRenderInstructionArray);
|
||||||
for (int i = 0, n = mRenderInstructions.size(); i < n; i++)
|
// for (int i = 0, n = mRenderInstructions.size(); i < n; i++)
|
||||||
mRenderInstructionArray[i] = mRenderInstructions.get(i);
|
// mRenderInstructionArray[i] = mRenderInstructions.get(i);
|
||||||
|
|
||||||
mSubRuleArray = new Rule[mSubRules.size()];
|
mSubRuleArray = new Rule[mSubRules.size()];
|
||||||
|
mSubRules.toArray(mSubRuleArray);
|
||||||
|
|
||||||
for (int i = 0, n = mSubRules.size(); i < n; i++)
|
// for (int i = 0, n = mSubRules.size(); i < n; i++)
|
||||||
mSubRuleArray[i] = mSubRules.get(i);
|
// mSubRuleArray[i] = mSubRules.get(i);
|
||||||
|
|
||||||
mRenderInstructions.clear();
|
mRenderInstructions.clear();
|
||||||
mRenderInstructions = null;
|
mRenderInstructions = null;
|
||||||
|
|||||||
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="src" type="tns:src" use="optional" />
|
||||||
<xs:attribute name="stroke" type="tns:color" use="optional"
|
<xs:attribute name="stroke" type="tns:color" use="optional"
|
||||||
default="#000000" />
|
default="#000000" />
|
||||||
<xs:attribute name="stroke-width" type="tns:nonNegativeFloat"
|
<xs:attribute name="width" type="tns:nonNegativeFloat"
|
||||||
use="optional" default="0" />
|
use="optional" default="0" />
|
||||||
<xs:attribute name="stroke-dasharray" type="tns:strokeDasharray"
|
<xs:attribute name="stroke-dasharray" type="tns:strokeDasharray"
|
||||||
use="optional" />
|
use="optional" />
|
||||||
<xs:attribute name="stroke-linecap" type="tns:cap" use="optional"
|
<xs:attribute name="cap" type="tns:cap" use="optional"
|
||||||
default="round" />
|
default="round" />
|
||||||
<xs:attribute name="outline" type="xs:integer" use="optional"
|
<xs:attribute name="outline" type="xs:integer" use="optional"
|
||||||
default="0" />
|
default="0" />
|
||||||
@ -163,6 +163,7 @@
|
|||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
|
|
||||||
<xs:complexType name="pathText">
|
<xs:complexType name="pathText">
|
||||||
|
<xs:attribute name="style" type="xs:string" use="optional" default="0"/>
|
||||||
<xs:attribute name="k" type="tns:textKey" use="required" />
|
<xs:attribute name="k" type="tns:textKey" use="required" />
|
||||||
<xs:attribute name="dy" type="xs:float" use="optional"
|
<xs:attribute name="dy" type="xs:float" use="optional"
|
||||||
default="0" />
|
default="0" />
|
||||||
@ -190,7 +191,7 @@
|
|||||||
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||||
<!-- recursion to allow for nested rules -->
|
<!-- recursion to allow for nested rules -->
|
||||||
<xs:element name="rule" type="tns:rule" />
|
<xs:element name="rule" type="tns:rule" />
|
||||||
|
|
||||||
<xs:element name="area" type="tns:area" />
|
<xs:element name="area" type="tns:area" />
|
||||||
<xs:element name="caption" type="tns:caption" />
|
<xs:element name="caption" type="tns:caption" />
|
||||||
<xs:element name="circle" type="tns:circle" />
|
<xs:element name="circle" type="tns:circle" />
|
||||||
@ -198,6 +199,7 @@
|
|||||||
<xs:element name="outline" type="tns:outline" />
|
<xs:element name="outline" type="tns:outline" />
|
||||||
<xs:element name="lineSymbol" type="tns:lineSymbol" />
|
<xs:element name="lineSymbol" type="tns:lineSymbol" />
|
||||||
<xs:element name="pathText" type="tns:pathText" />
|
<xs:element name="pathText" type="tns:pathText" />
|
||||||
|
<xs:element name="stylePathText type="xs:string" />
|
||||||
<xs:element name="symbol" type="tns:symbol" />
|
<xs:element name="symbol" type="tns:symbol" />
|
||||||
</xs:choice>
|
</xs:choice>
|
||||||
<xs:attribute name="e" type="tns:elementList" use="required" />
|
<xs:attribute name="e" type="tns:elementList" use="required" />
|
||||||
@ -214,6 +216,12 @@
|
|||||||
|
|
||||||
<!-- rendertheme element -->
|
<!-- rendertheme element -->
|
||||||
<xs:complexType name="rendertheme">
|
<xs:complexType name="rendertheme">
|
||||||
|
<xs:sequence minOccurs="0" maxOccurds="256">
|
||||||
|
<xs:choice minOccurs="0" maxOccurs="unbounded">
|
||||||
|
<xs:element name="style-pathtext" type="tns:pathText" />
|
||||||
|
<xs:element name="style-area" type="tns:area" />
|
||||||
|
</xs:choice>
|
||||||
|
</xs:sequence)
|
||||||
<xs:sequence minOccurs="0" maxOccurs="unbounded">
|
<xs:sequence minOccurs="0" maxOccurs="unbounded">
|
||||||
<xs:element name="rule" type="tns:rule" />
|
<xs:element name="rule" type="tns:rule" />
|
||||||
</xs:sequence>
|
</xs:sequence>
|
||||||
|
|||||||
@ -14,23 +14,17 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapsforge.android.rendertheme.renderinstruction;
|
package org.mapsforge.android.rendertheme.renderinstruction;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.mapsforge.android.rendertheme.IRenderCallback;
|
import org.mapsforge.android.rendertheme.IRenderCallback;
|
||||||
import org.mapsforge.android.rendertheme.RenderThemeHandler;
|
import org.mapsforge.android.rendertheme.RenderThemeHandler;
|
||||||
import org.mapsforge.core.Tag;
|
import org.mapsforge.core.Tag;
|
||||||
import org.xml.sax.Attributes;
|
import org.xml.sax.Attributes;
|
||||||
|
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.Paint;
|
|
||||||
import android.graphics.Paint.Cap;
|
|
||||||
import android.graphics.Paint.Style;
|
|
||||||
import android.graphics.Shader;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a closed polygon on the map.
|
* Represents a closed polygon on the map.
|
||||||
*/
|
*/
|
||||||
public final class Area implements RenderInstruction {
|
public final class Area extends RenderInstruction {
|
||||||
/**
|
/**
|
||||||
* @param elementName
|
* @param elementName
|
||||||
* the name of the XML element.
|
* the name of the XML element.
|
||||||
@ -39,11 +33,8 @@ public final class Area implements RenderInstruction {
|
|||||||
* @param level
|
* @param level
|
||||||
* the drawing level of this instruction.
|
* the drawing level of this instruction.
|
||||||
* @return a new Area with the given rendering attributes.
|
* @return a new Area with the given rendering attributes.
|
||||||
* @throws IOException
|
|
||||||
* if an I/O error occurs while reading a resource.
|
|
||||||
*/
|
*/
|
||||||
public static Area create(String elementName, Attributes attributes, int level)
|
public static Area create(String elementName, Attributes attributes, int level) {
|
||||||
throws IOException {
|
|
||||||
String src = null;
|
String src = null;
|
||||||
int fill = Color.BLACK;
|
int fill = Color.BLACK;
|
||||||
int stroke = Color.TRANSPARENT;
|
int stroke = Color.TRANSPARENT;
|
||||||
@ -51,12 +42,14 @@ public final class Area implements RenderInstruction {
|
|||||||
int fade = -1;
|
int fade = -1;
|
||||||
int blend = -1;
|
int blend = -1;
|
||||||
int blendFill = Color.BLACK;
|
int blendFill = Color.BLACK;
|
||||||
|
String style = null;
|
||||||
|
|
||||||
for (int i = 0; i < attributes.getLength(); ++i) {
|
for (int i = 0; i < attributes.getLength(); ++i) {
|
||||||
String name = attributes.getLocalName(i);
|
String name = attributes.getLocalName(i);
|
||||||
String value = attributes.getValue(i);
|
String value = attributes.getValue(i);
|
||||||
|
if ("name".equals(name))
|
||||||
if ("src".equals(name)) {
|
style = value;
|
||||||
|
else if ("src".equals(name)) {
|
||||||
src = value;
|
src = value;
|
||||||
} else if ("fill".equals(name)) {
|
} else if ("fill".equals(name)) {
|
||||||
fill = Color.parseColor(value);
|
fill = Color.parseColor(value);
|
||||||
@ -76,7 +69,8 @@ public final class Area implements RenderInstruction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
validate(strokeWidth);
|
validate(strokeWidth);
|
||||||
return new Area(src, fill, stroke, strokeWidth, fade, level, blend, blendFill);
|
return new Area(style, src, fill, stroke, strokeWidth, fade, level, blend,
|
||||||
|
blendFill);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void validate(float strokeWidth) {
|
private static void validate(float strokeWidth) {
|
||||||
@ -86,32 +80,38 @@ public final class Area implements RenderInstruction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Area(String src, int fill, int stroke, float strokeWidth, int fade,
|
private Area(String style, String src, int fill, int stroke, float strokeWidth,
|
||||||
int level, int blend, int blendFill)
|
int fade, int level, int blend, int blendFill) {
|
||||||
throws IOException {
|
|
||||||
super();
|
super();
|
||||||
|
this.style = style;
|
||||||
|
|
||||||
if (fill == Color.TRANSPARENT) {
|
// if (fill == Color.TRANSPARENT) {
|
||||||
paintFill = null;
|
// paintFill = null;
|
||||||
} else {
|
// } else {
|
||||||
paintFill = new Paint(Paint.ANTI_ALIAS_FLAG);
|
// paintFill = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||||
if (src != null) {
|
// if (src != null) {
|
||||||
Shader shader = BitmapUtils.createBitmapShader(src);
|
// Shader shader = BitmapUtils.createBitmapShader(src);
|
||||||
paintFill.setShader(shader);
|
// paintFill.setShader(shader);
|
||||||
}
|
// }
|
||||||
paintFill.setStyle(Style.FILL);
|
// paintFill.setStyle(Style.FILL);
|
||||||
paintFill.setColor(fill);
|
// paintFill.setColor(fill);
|
||||||
paintFill.setStrokeCap(Cap.ROUND);
|
// paintFill.setStrokeCap(Cap.ROUND);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
|
// if (stroke == Color.TRANSPARENT) {
|
||||||
|
// paintOutline = null;
|
||||||
|
// } else {
|
||||||
|
// paintOutline = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||||
|
// paintOutline.setStyle(Style.STROKE);
|
||||||
|
// paintOutline.setColor(stroke);
|
||||||
|
// paintOutline.setStrokeCap(Cap.ROUND);
|
||||||
|
// }
|
||||||
|
|
||||||
if (stroke == Color.TRANSPARENT) {
|
// if (stroke == Color.TRANSPARENT) {
|
||||||
paintOutline = null;
|
// stroke = null;
|
||||||
} else {
|
// } else{
|
||||||
paintOutline = new Paint(Paint.ANTI_ALIAS_FLAG);
|
// stroke = new Line()
|
||||||
paintOutline.setStyle(Style.STROKE);
|
// }
|
||||||
paintOutline.setColor(stroke);
|
|
||||||
paintOutline.setStrokeCap(Cap.ROUND);
|
|
||||||
}
|
|
||||||
|
|
||||||
color = new float[4];
|
color = new float[4];
|
||||||
color[0] = (fill >> 16 & 0xff) / 255.0f;
|
color[0] = (fill >> 16 & 0xff) / 255.0f;
|
||||||
@ -135,47 +135,31 @@ public final class Area implements RenderInstruction {
|
|||||||
this.level = level;
|
this.level = level;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void destroy() {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void renderNode(IRenderCallback renderCallback, Tag[] tags) {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void renderWay(IRenderCallback renderCallback, Tag[] tags) {
|
public void renderWay(IRenderCallback renderCallback, Tag[] tags) {
|
||||||
if (paintFill != null) {
|
renderCallback.renderArea(this, this.level);
|
||||||
renderCallback.renderArea(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
// @Override
|
||||||
public void scaleStrokeWidth(float scaleFactor) {
|
// public void scaleStrokeWidth(float scaleFactor) {
|
||||||
if (paintOutline != null) {
|
// // if (paintOutline != null) {
|
||||||
paintOutline.setStrokeWidth(strokeWidth * scaleFactor);
|
// // paintOutline.setStrokeWidth(strokeWidth * scaleFactor);
|
||||||
}
|
// // }
|
||||||
}
|
// }
|
||||||
|
|
||||||
@Override
|
|
||||||
public void scaleTextSize(float scaleFactor) {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
|
public String style;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public final int level;
|
private final int level;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public final Paint paintFill;
|
// public final Paint paintFill;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public final Paint paintOutline;
|
// public final Paint paintOutline;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -12,17 +12,22 @@
|
|||||||
* You should have received a copy of the GNU Lesser General Public License along with
|
* You should have received a copy of the GNU Lesser General Public License along with
|
||||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
package org.mapsforge.android.glrenderer;
|
package org.mapsforge.android.rendertheme.renderinstruction;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import org.mapsforge.android.rendertheme.IRenderCallback;
|
||||||
|
import org.mapsforge.core.Tag;
|
||||||
|
|
||||||
import org.mapsforge.android.rendertheme.renderinstruction.Caption;
|
public class AreaLevel extends RenderInstruction {
|
||||||
|
private final Area area;
|
||||||
public class TextLayer {
|
private final int level;
|
||||||
public ArrayList<TextItem> labels;
|
|
||||||
|
|
||||||
void addLabel(float x, float y, String text, Caption caption) {
|
|
||||||
|
|
||||||
|
public AreaLevel(Area area, int level) {
|
||||||
|
this.area = area;
|
||||||
|
this.level = level;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void renderWay(IRenderCallback renderCallback, Tag[] tags) {
|
||||||
|
renderCallback.renderArea(this.area, level);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -32,7 +32,7 @@ import android.util.FloatMath;
|
|||||||
/**
|
/**
|
||||||
* Represents a text label on the map.
|
* Represents a text label on the map.
|
||||||
*/
|
*/
|
||||||
public final class Caption implements RenderInstruction {
|
public final class Caption extends RenderInstruction {
|
||||||
/**
|
/**
|
||||||
* @param elementName
|
* @param elementName
|
||||||
* the name of the XML element.
|
* the name of the XML element.
|
||||||
@ -130,11 +130,6 @@ public final class Caption implements RenderInstruction {
|
|||||||
fontDescent = FloatMath.ceil(Math.abs(fm.descent));
|
fontDescent = FloatMath.ceil(Math.abs(fm.descent));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void destroy() {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void renderNode(IRenderCallback renderCallback, Tag[] tags) {
|
public void renderNode(IRenderCallback renderCallback, Tag[] tags) {
|
||||||
renderCallback.renderPointOfInterestCaption(this);
|
renderCallback.renderPointOfInterestCaption(this);
|
||||||
@ -145,11 +140,6 @@ public final class Caption implements RenderInstruction {
|
|||||||
renderCallback.renderAreaCaption(this);
|
renderCallback.renderAreaCaption(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void scaleStrokeWidth(float scaleFactor) {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void scaleTextSize(float scaleFactor) {
|
public void scaleTextSize(float scaleFactor) {
|
||||||
paint.setTextSize(fontSize * scaleFactor);
|
paint.setTextSize(fontSize * scaleFactor);
|
||||||
|
|||||||
@ -26,7 +26,7 @@ import android.graphics.Paint.Style;
|
|||||||
/**
|
/**
|
||||||
* Represents a round area on the map.
|
* Represents a round area on the map.
|
||||||
*/
|
*/
|
||||||
public final class Circle implements RenderInstruction {
|
public final class Circle extends RenderInstruction {
|
||||||
/**
|
/**
|
||||||
* @param elementName
|
* @param elementName
|
||||||
* the name of the XML element.
|
* the name of the XML element.
|
||||||
@ -68,11 +68,13 @@ public final class Circle implements RenderInstruction {
|
|||||||
|
|
||||||
private static void validate(String elementName, Float radius, float strokeWidth) {
|
private static void validate(String elementName, Float radius, float strokeWidth) {
|
||||||
if (radius == null) {
|
if (radius == null) {
|
||||||
throw new IllegalArgumentException("missing attribute r for element: " + elementName);
|
throw new IllegalArgumentException("missing attribute r for element: "
|
||||||
|
+ elementName);
|
||||||
} else if (radius.floatValue() < 0) {
|
} else if (radius.floatValue() < 0) {
|
||||||
throw new IllegalArgumentException("radius must not be negative: " + radius);
|
throw new IllegalArgumentException("radius must not be negative: " + radius);
|
||||||
} else if (strokeWidth < 0) {
|
} else if (strokeWidth < 0) {
|
||||||
throw new IllegalArgumentException("stroke-width must not be negative: " + strokeWidth);
|
throw new IllegalArgumentException("stroke-width must not be negative: "
|
||||||
|
+ strokeWidth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,7 +86,8 @@ public final class Circle implements RenderInstruction {
|
|||||||
private final boolean mScaleRadius;
|
private final boolean mScaleRadius;
|
||||||
private final float mStrokeWidth;
|
private final float mStrokeWidth;
|
||||||
|
|
||||||
private Circle(Float radius, boolean scaleRadius, int fill, int stroke, float strokeWidth, int level) {
|
private Circle(Float radius, boolean scaleRadius, int fill, int stroke,
|
||||||
|
float strokeWidth, int level) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
mRadius = radius.floatValue();
|
mRadius = radius.floatValue();
|
||||||
@ -117,11 +120,6 @@ public final class Circle implements RenderInstruction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void destroy() {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void renderNode(IRenderCallback renderCallback, Tag[] tags) {
|
public void renderNode(IRenderCallback renderCallback, Tag[] tags) {
|
||||||
if (mOutline != null) {
|
if (mOutline != null) {
|
||||||
@ -132,11 +130,6 @@ public final class Circle implements RenderInstruction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void renderWay(IRenderCallback renderCallback, Tag[] tags) {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void scaleStrokeWidth(float scaleFactor) {
|
public void scaleStrokeWidth(float scaleFactor) {
|
||||||
if (mScaleRadius) {
|
if (mScaleRadius) {
|
||||||
@ -146,9 +139,4 @@ public final class Circle implements RenderInstruction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void scaleTextSize(float scaleFactor) {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,7 +14,6 @@
|
|||||||
*/
|
*/
|
||||||
package org.mapsforge.android.rendertheme.renderinstruction;
|
package org.mapsforge.android.rendertheme.renderinstruction;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
@ -24,73 +23,94 @@ import org.mapsforge.core.Tag;
|
|||||||
import org.xml.sax.Attributes;
|
import org.xml.sax.Attributes;
|
||||||
|
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.DashPathEffect;
|
|
||||||
import android.graphics.Paint;
|
|
||||||
import android.graphics.Paint.Cap;
|
import android.graphics.Paint.Cap;
|
||||||
import android.graphics.Paint.Style;
|
|
||||||
import android.graphics.Shader;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a polyline on the map.
|
* Represents a polyline on the map.
|
||||||
*/
|
*/
|
||||||
public final class Line implements RenderInstruction {
|
public final class Line extends RenderInstruction {
|
||||||
private static final Pattern SPLIT_PATTERN = Pattern.compile(",");
|
private static final Pattern SPLIT_PATTERN = Pattern.compile(",");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param line
|
||||||
|
* ...
|
||||||
* @param elementName
|
* @param elementName
|
||||||
* the name of the XML element.
|
* the name of the XML element.
|
||||||
* @param attributes
|
* @param attributes
|
||||||
* the attributes of the XML element.
|
* the attributes of the XML element.
|
||||||
* @param level
|
* @param level
|
||||||
* the drawing level of this instruction.
|
* the drawing level of this instruction.
|
||||||
|
* @param isOutline
|
||||||
|
* ...
|
||||||
* @return a new Line with the given rendering attributes.
|
* @return a new Line with the given rendering attributes.
|
||||||
* @throws IOException
|
|
||||||
* if an I/O error occurs while reading a resource.
|
|
||||||
*/
|
*/
|
||||||
public static Line create(String elementName, Attributes attributes, int level)
|
public static Line create(Line line, String elementName, Attributes attributes,
|
||||||
throws IOException {
|
int level, boolean isOutline) {
|
||||||
String src = null;
|
String src = null;
|
||||||
int stroke = Color.BLACK;
|
int stroke = Color.BLACK;
|
||||||
float strokeWidth = 0;
|
float strokeWidth = 0;
|
||||||
float[] strokeDasharray = null;
|
float[] strokeDasharray = null;
|
||||||
Cap strokeLinecap = Cap.ROUND;
|
Cap strokeLinecap = Cap.ROUND;
|
||||||
int outline = -1;
|
|
||||||
int fade = -1;
|
int fade = -1;
|
||||||
boolean fixed = false;
|
boolean fixed = false;
|
||||||
|
String style = null;
|
||||||
|
float blur = 0;
|
||||||
|
|
||||||
|
if (line != null) {
|
||||||
|
fixed = line.fixed;
|
||||||
|
fade = line.fade;
|
||||||
|
strokeLinecap = line.cap;
|
||||||
|
blur = line.blur;
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < attributes.getLength(); ++i) {
|
for (int i = 0; i < attributes.getLength(); ++i) {
|
||||||
String name = attributes.getLocalName(i);
|
String name = attributes.getLocalName(i);
|
||||||
String value = attributes.getValue(i);
|
String value = attributes.getValue(i);
|
||||||
|
|
||||||
if ("src".equals(name)) {
|
if ("name".equals(name))
|
||||||
|
style = value;
|
||||||
|
else if ("src".equals(name)) {
|
||||||
src = value;
|
src = value;
|
||||||
} else if ("stroke".equals(name)) {
|
} else if ("stroke".equals(name)) {
|
||||||
stroke = Color.parseColor(value);
|
stroke = Color.parseColor(value);
|
||||||
} else if ("stroke-width".equals(name)) {
|
} else if ("width".equals(name)) {
|
||||||
strokeWidth = Float.parseFloat(value);
|
strokeWidth = Float.parseFloat(value);
|
||||||
} else if ("stroke-dasharray".equals(name)) {
|
} else if ("stroke-dasharray".equals(name)) {
|
||||||
strokeDasharray = parseFloatArray(value);
|
strokeDasharray = parseFloatArray(value);
|
||||||
} else if ("stroke-linecap".equals(name)) {
|
} else if ("cap".equals(name)) {
|
||||||
strokeLinecap = Cap.valueOf(value.toUpperCase(Locale.ENGLISH));
|
strokeLinecap = Cap.valueOf(value.toUpperCase(Locale.ENGLISH));
|
||||||
} else if ("outline".equals(name)) {
|
|
||||||
outline = Integer.parseInt(value);
|
|
||||||
} else if ("fade".equals(name)) {
|
} else if ("fade".equals(name)) {
|
||||||
fade = Integer.parseInt(value);
|
fade = Integer.parseInt(value);
|
||||||
} else if ("fixed".equals(name)) {
|
} else if ("fixed".equals(name)) {
|
||||||
fixed = Boolean.parseBoolean(value);
|
fixed = Boolean.parseBoolean(value);
|
||||||
|
} else if ("blur".equals(name)) {
|
||||||
|
blur = Float.parseFloat(value);
|
||||||
|
} else if ("from".equals(name)) {
|
||||||
} else {
|
} else {
|
||||||
RenderThemeHandler.logUnknownAttribute(elementName, name, value, i);
|
RenderThemeHandler.logUnknownAttribute(elementName, name, value, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
validate(strokeWidth);
|
if (line != null) {
|
||||||
return new Line(src, stroke, strokeWidth, strokeDasharray, strokeLinecap, level,
|
|
||||||
outline, fixed, fade);
|
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) {
|
private static void validate(float strokeWidth) {
|
||||||
if (strokeWidth < 0) {
|
if (strokeWidth < 0) {
|
||||||
throw new IllegalArgumentException("stroke-width must not be negative: "
|
throw new IllegalArgumentException("width must not be negative: "
|
||||||
+ strokeWidth);
|
+ strokeWidth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -107,15 +127,15 @@ public final class Line implements RenderInstruction {
|
|||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public final int level;
|
private final int level;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public final Paint paint;
|
// public final Paint paint;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public final float strokeWidth;
|
public final float width;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@ -127,7 +147,7 @@ public final class Line implements RenderInstruction {
|
|||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public final int outline;
|
public final boolean outline;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -136,60 +156,83 @@ public final class Line implements RenderInstruction {
|
|||||||
|
|
||||||
public final int fade;
|
public final int fade;
|
||||||
|
|
||||||
private Line(String src, int stroke, float strokeWidth, float[] strokeDasharray,
|
public final String style;
|
||||||
Cap strokeLinecap, int level,
|
|
||||||
int outline, boolean fixed, int fade)
|
public final Cap cap;
|
||||||
throws IOException {
|
|
||||||
|
public final float blur;
|
||||||
|
|
||||||
|
private Line(String style, String src, int stroke, float strokeWidth,
|
||||||
|
float[] strokeDasharray, Cap strokeLinecap, int level, boolean fixed,
|
||||||
|
int fade, float blur, boolean isOutline) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
Shader shader = BitmapUtils.createBitmapShader(src);
|
this.style = style;
|
||||||
|
|
||||||
|
// paint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||||
|
//
|
||||||
|
// if (src != null) {
|
||||||
|
// Shader shader = BitmapUtils.createBitmapShader(src);
|
||||||
|
// paint.setShader(shader);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// paint.setStyle(Style.STROKE);
|
||||||
|
// paint.setColor(stroke);
|
||||||
|
// if (strokeDasharray != null) {
|
||||||
|
// paint.setPathEffect(new DashPathEffect(strokeDasharray, 0));
|
||||||
|
// }
|
||||||
|
// paint.setStrokeCap(strokeLinecap);
|
||||||
|
|
||||||
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
|
||||||
paint.setShader(shader);
|
|
||||||
paint.setStyle(Style.STROKE);
|
|
||||||
paint.setColor(stroke);
|
|
||||||
if (strokeDasharray != null) {
|
|
||||||
paint.setPathEffect(new DashPathEffect(strokeDasharray, 0));
|
|
||||||
}
|
|
||||||
paint.setStrokeCap(strokeLinecap);
|
|
||||||
round = (strokeLinecap == Cap.ROUND);
|
round = (strokeLinecap == Cap.ROUND);
|
||||||
|
|
||||||
|
this.cap = strokeLinecap;
|
||||||
|
|
||||||
color = new float[4];
|
color = new float[4];
|
||||||
color[0] = (stroke >> 16 & 0xff) / 255.0f;
|
color[0] = (stroke >> 16 & 0xff) / 255.0f;
|
||||||
color[1] = (stroke >> 8 & 0xff) / 255.0f;
|
color[1] = (stroke >> 8 & 0xff) / 255.0f;
|
||||||
color[2] = (stroke >> 0 & 0xff) / 255.0f;
|
color[2] = (stroke >> 0 & 0xff) / 255.0f;
|
||||||
color[3] = (stroke >> 24 & 0xff) / 255.0f;
|
color[3] = (stroke >> 24 & 0xff) / 255.0f;
|
||||||
|
|
||||||
this.strokeWidth = strokeWidth;
|
this.width = strokeWidth;
|
||||||
this.level = level;
|
this.level = level;
|
||||||
this.outline = outline;
|
this.outline = isOutline;
|
||||||
this.fixed = fixed;
|
this.fixed = fixed;
|
||||||
|
this.blur = blur;
|
||||||
this.fade = fade;
|
this.fade = fade;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private Line(Line line, String style, String src, int stroke, float strokeWidth,
|
||||||
public void destroy() {
|
float[] strokeDasharray, Cap strokeLinecap, int level, boolean fixed,
|
||||||
// do nothing
|
int fade, float blur, boolean isOutline) {
|
||||||
}
|
super();
|
||||||
|
|
||||||
@Override
|
this.style = style;
|
||||||
public void renderNode(IRenderCallback renderCallback, Tag[] tags) {
|
|
||||||
// do nothing
|
round = (strokeLinecap == Cap.ROUND);
|
||||||
|
|
||||||
|
color = line.color;
|
||||||
|
|
||||||
|
this.width = strokeWidth;
|
||||||
|
this.level = level;
|
||||||
|
this.outline = isOutline;
|
||||||
|
this.fixed = fixed;
|
||||||
|
this.fade = fade;
|
||||||
|
this.cap = strokeLinecap;
|
||||||
|
this.blur = blur;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void renderWay(IRenderCallback renderCallback, Tag[] tags) {
|
public void renderWay(IRenderCallback renderCallback, Tag[] tags) {
|
||||||
// renderCallback.renderWay(mPaint, mLevel, mColor, mStrokeWidth, mRound, mOutline);
|
// renderCallback.renderWay(mPaint, mLevel, mColor, mStrokeWidth, mRound, mOutline);
|
||||||
renderCallback.renderWay(this);
|
renderCallback.renderWay(this, level);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
// @Override
|
||||||
public void scaleStrokeWidth(float scaleFactor) {
|
// public void scaleStrokeWidth(float scaleFactor) {
|
||||||
paint.setStrokeWidth(strokeWidth * scaleFactor);
|
// paint.setStrokeWidth(strokeWidth * scaleFactor);
|
||||||
}
|
// }
|
||||||
|
|
||||||
@Override
|
public int getLevel() {
|
||||||
public void scaleTextSize(float scaleFactor) {
|
return this.level;
|
||||||
// do nothing
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,7 +26,7 @@ import android.graphics.Bitmap;
|
|||||||
/**
|
/**
|
||||||
* Represents an icon along a polyline on the map.
|
* Represents an icon along a polyline on the map.
|
||||||
*/
|
*/
|
||||||
public final class LineSymbol implements RenderInstruction {
|
public final class LineSymbol extends RenderInstruction {
|
||||||
/**
|
/**
|
||||||
* @param elementName
|
* @param elementName
|
||||||
* the name of the XML element.
|
* the name of the XML element.
|
||||||
@ -36,7 +36,8 @@ public final class LineSymbol implements RenderInstruction {
|
|||||||
* @throws IOException
|
* @throws IOException
|
||||||
* if an I/O error occurs while reading a resource.
|
* if an I/O error occurs while reading a resource.
|
||||||
*/
|
*/
|
||||||
public static LineSymbol create(String elementName, Attributes attributes) throws IOException {
|
public static LineSymbol create(String elementName, Attributes attributes)
|
||||||
|
throws IOException {
|
||||||
String src = null;
|
String src = null;
|
||||||
boolean alignCenter = false;
|
boolean alignCenter = false;
|
||||||
boolean repeat = false;
|
boolean repeat = false;
|
||||||
@ -62,7 +63,8 @@ public final class LineSymbol implements RenderInstruction {
|
|||||||
|
|
||||||
private static void validate(String elementName, String src) {
|
private static void validate(String elementName, String src) {
|
||||||
if (src == null) {
|
if (src == null) {
|
||||||
throw new IllegalArgumentException("missing attribute src for element: " + elementName);
|
throw new IllegalArgumentException("missing attribute src for element: "
|
||||||
|
+ elementName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,7 +72,8 @@ public final class LineSymbol implements RenderInstruction {
|
|||||||
private final Bitmap mBitmap;
|
private final Bitmap mBitmap;
|
||||||
private final boolean mRepeat;
|
private final boolean mRepeat;
|
||||||
|
|
||||||
private LineSymbol(String src, boolean alignCenter, boolean repeat) throws IOException {
|
private LineSymbol(String src, boolean alignCenter, boolean repeat)
|
||||||
|
throws IOException {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
mBitmap = BitmapUtils.createBitmap(src);
|
mBitmap = BitmapUtils.createBitmap(src);
|
||||||
@ -83,23 +86,8 @@ public final class LineSymbol implements RenderInstruction {
|
|||||||
mBitmap.recycle();
|
mBitmap.recycle();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void renderNode(IRenderCallback renderCallback, Tag[] tags) {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void renderWay(IRenderCallback renderCallback, Tag[] tags) {
|
public void renderWay(IRenderCallback renderCallback, Tag[] tags) {
|
||||||
renderCallback.renderWaySymbol(mBitmap, mAlignCenter, mRepeat);
|
renderCallback.renderWaySymbol(mBitmap, mAlignCenter, mRepeat);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void scaleStrokeWidth(float scaleFactor) {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void scaleTextSize(float scaleFactor) {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,13 +24,15 @@ import org.xml.sax.Attributes;
|
|||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
import android.graphics.Paint.Align;
|
import android.graphics.Paint.Align;
|
||||||
|
import android.graphics.Paint.FontMetrics;
|
||||||
import android.graphics.Paint.Style;
|
import android.graphics.Paint.Style;
|
||||||
import android.graphics.Typeface;
|
import android.graphics.Typeface;
|
||||||
|
import android.util.FloatMath;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a text along a polyline on the map.
|
* Represents a text along a polyline on the map.
|
||||||
*/
|
*/
|
||||||
public final class PathText implements RenderInstruction {
|
public final class PathText extends RenderInstruction {
|
||||||
/**
|
/**
|
||||||
* @param elementName
|
* @param elementName
|
||||||
* the name of the XML element.
|
* the name of the XML element.
|
||||||
@ -46,12 +48,14 @@ public final class PathText implements RenderInstruction {
|
|||||||
int fill = Color.BLACK;
|
int fill = Color.BLACK;
|
||||||
int stroke = Color.BLACK;
|
int stroke = Color.BLACK;
|
||||||
float strokeWidth = 0;
|
float strokeWidth = 0;
|
||||||
|
String style = null;
|
||||||
|
|
||||||
for (int i = 0; i < attributes.getLength(); ++i) {
|
for (int i = 0; i < attributes.getLength(); ++i) {
|
||||||
String name = attributes.getLocalName(i);
|
String name = attributes.getLocalName(i);
|
||||||
String value = attributes.getValue(i);
|
String value = attributes.getValue(i);
|
||||||
|
if ("name".equals(name))
|
||||||
if ("k".equals(name)) {
|
style = value;
|
||||||
|
else if ("k".equals(name)) {
|
||||||
textKey = TextKey.getInstance(value);
|
textKey = TextKey.getInstance(value);
|
||||||
} else if ("font-family".equals(name)) {
|
} else if ("font-family".equals(name)) {
|
||||||
fontFamily = FontFamily.valueOf(value.toUpperCase(Locale.ENGLISH));
|
fontFamily = FontFamily.valueOf(value.toUpperCase(Locale.ENGLISH));
|
||||||
@ -72,67 +76,69 @@ public final class PathText implements RenderInstruction {
|
|||||||
|
|
||||||
validate(elementName, textKey, fontSize, strokeWidth);
|
validate(elementName, textKey, fontSize, strokeWidth);
|
||||||
Typeface typeface = Typeface.create(fontFamily.toTypeface(), fontStyle.toInt());
|
Typeface typeface = Typeface.create(fontFamily.toTypeface(), fontStyle.toInt());
|
||||||
return new PathText(textKey, typeface, fontSize, fill, stroke, strokeWidth);
|
return new PathText(style, textKey, typeface, fontSize, fill, stroke, strokeWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void validate(String elementName, String textKey, float fontSize, float strokeWidth) {
|
private static void validate(String elementName, String textKey, float fontSize,
|
||||||
|
float strokeWidth) {
|
||||||
if (textKey == null) {
|
if (textKey == null) {
|
||||||
throw new IllegalArgumentException("missing attribute k for element: " + elementName);
|
throw new IllegalArgumentException("missing attribute k for element: "
|
||||||
|
+ elementName);
|
||||||
} else if (fontSize < 0) {
|
} else if (fontSize < 0) {
|
||||||
throw new IllegalArgumentException("font-size must not be negative: " + fontSize);
|
throw new IllegalArgumentException("font-size must not be negative: "
|
||||||
|
+ fontSize);
|
||||||
} else if (strokeWidth < 0) {
|
} else if (strokeWidth < 0) {
|
||||||
throw new IllegalArgumentException("stroke-width must not be negative: " + strokeWidth);
|
throw new IllegalArgumentException("stroke-width must not be negative: "
|
||||||
|
+ strokeWidth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final float mFontSize;
|
public final float fontSize;
|
||||||
private final Paint mPaint;
|
public final Paint paint;
|
||||||
private final Paint mStroke;
|
public Paint stroke;
|
||||||
private final String mTextKey;
|
public String textKey;
|
||||||
|
public final float fontHeight;
|
||||||
|
public final float fontDescent;
|
||||||
|
public String style;
|
||||||
|
|
||||||
private PathText(String textKey, Typeface typeface, float fontSize, int fill, int stroke, float strokeWidth) {
|
private PathText(String style, String textKey, Typeface typeface, float fontSize,
|
||||||
|
int fill, int outline, float strokeWidth) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
mTextKey = textKey;
|
this.style = style;
|
||||||
|
|
||||||
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
this.textKey = textKey;
|
||||||
mPaint.setTextAlign(Align.CENTER);
|
|
||||||
mPaint.setTypeface(typeface);
|
|
||||||
mPaint.setColor(fill);
|
|
||||||
|
|
||||||
mStroke = new Paint(Paint.ANTI_ALIAS_FLAG);
|
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||||
mStroke.setStyle(Style.STROKE);
|
paint.setTextAlign(Align.CENTER);
|
||||||
mStroke.setTextAlign(Align.CENTER);
|
paint.setTypeface(typeface);
|
||||||
mStroke.setTypeface(typeface);
|
paint.setColor(fill);
|
||||||
mStroke.setColor(stroke);
|
|
||||||
mStroke.setStrokeWidth(strokeWidth);
|
|
||||||
|
|
||||||
mFontSize = fontSize;
|
stroke = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||||
}
|
stroke.setStyle(Style.STROKE);
|
||||||
|
stroke.setTextAlign(Align.CENTER);
|
||||||
|
stroke.setTypeface(typeface);
|
||||||
|
stroke.setColor(outline);
|
||||||
|
stroke.setStrokeWidth(strokeWidth);
|
||||||
|
|
||||||
@Override
|
this.fontSize = fontSize;
|
||||||
public void destroy() {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
paint.setTextSize(fontSize);
|
||||||
public void renderNode(IRenderCallback renderCallback, Tag[] tags) {
|
stroke.setTextSize(fontSize);
|
||||||
// do nothing
|
|
||||||
|
FontMetrics fm = paint.getFontMetrics();
|
||||||
|
fontHeight = FloatMath.ceil(Math.abs(fm.bottom) + Math.abs(fm.top));
|
||||||
|
fontDescent = FloatMath.ceil(Math.abs(fm.descent));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void renderWay(IRenderCallback renderCallback, Tag[] tags) {
|
public void renderWay(IRenderCallback renderCallback, Tag[] tags) {
|
||||||
renderCallback.renderWayText(mTextKey, mPaint, mStroke);
|
renderCallback.renderWayText(this);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void scaleStrokeWidth(float scaleFactor) {
|
|
||||||
// do nothing
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void scaleTextSize(float scaleFactor) {
|
public void scaleTextSize(float scaleFactor) {
|
||||||
mPaint.setTextSize(mFontSize * scaleFactor);
|
paint.setTextSize(fontSize * scaleFactor);
|
||||||
mStroke.setTextSize(mFontSize * scaleFactor);
|
stroke.setTextSize(fontSize * scaleFactor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,11 +20,12 @@ import org.mapsforge.core.Tag;
|
|||||||
/**
|
/**
|
||||||
* A RenderInstruction is a basic graphical primitive to draw a map.
|
* A RenderInstruction is a basic graphical primitive to draw a map.
|
||||||
*/
|
*/
|
||||||
public interface RenderInstruction {
|
public abstract class RenderInstruction {
|
||||||
/**
|
/**
|
||||||
* Destroys this RenderInstruction and cleans up all its internal resources.
|
* Destroys this RenderInstruction and cleans up all its internal resources.
|
||||||
*/
|
*/
|
||||||
void destroy();
|
public void destroy() {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param renderCallback
|
* @param renderCallback
|
||||||
@ -32,7 +33,8 @@ public interface RenderInstruction {
|
|||||||
* @param tags
|
* @param tags
|
||||||
* the tags of the node.
|
* the tags of the node.
|
||||||
*/
|
*/
|
||||||
void renderNode(IRenderCallback renderCallback, Tag[] tags);
|
public void renderNode(IRenderCallback renderCallback, Tag[] tags) {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param renderCallback
|
* @param renderCallback
|
||||||
@ -40,7 +42,8 @@ public interface RenderInstruction {
|
|||||||
* @param tags
|
* @param tags
|
||||||
* the tags of the way.
|
* the tags of the way.
|
||||||
*/
|
*/
|
||||||
void renderWay(IRenderCallback renderCallback, Tag[] tags);
|
public void renderWay(IRenderCallback renderCallback, Tag[] tags) {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scales the stroke width of this RenderInstruction by the given factor.
|
* Scales the stroke width of this RenderInstruction by the given factor.
|
||||||
@ -48,7 +51,8 @@ public interface RenderInstruction {
|
|||||||
* @param scaleFactor
|
* @param scaleFactor
|
||||||
* the factor by which the stroke width should be scaled.
|
* the factor by which the stroke width should be scaled.
|
||||||
*/
|
*/
|
||||||
void scaleStrokeWidth(float scaleFactor);
|
public void scaleStrokeWidth(float scaleFactor) {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scales the text size of this RenderInstruction by the given factor.
|
* Scales the text size of this RenderInstruction by the given factor.
|
||||||
@ -56,5 +60,6 @@ public interface RenderInstruction {
|
|||||||
* @param scaleFactor
|
* @param scaleFactor
|
||||||
* the factor by which the text size should be scaled.
|
* the factor by which the text size should be scaled.
|
||||||
*/
|
*/
|
||||||
void scaleTextSize(float scaleFactor);
|
public void scaleTextSize(float scaleFactor) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,7 +26,7 @@ import android.graphics.Bitmap;
|
|||||||
/**
|
/**
|
||||||
* Represents an icon on the map.
|
* Represents an icon on the map.
|
||||||
*/
|
*/
|
||||||
public final class Symbol implements RenderInstruction {
|
public final class Symbol extends RenderInstruction {
|
||||||
/**
|
/**
|
||||||
* @param elementName
|
* @param elementName
|
||||||
* the name of the XML element.
|
* the name of the XML element.
|
||||||
@ -36,7 +36,8 @@ public final class Symbol implements RenderInstruction {
|
|||||||
* @throws IOException
|
* @throws IOException
|
||||||
* if an I/O error occurs while reading a resource.
|
* if an I/O error occurs while reading a resource.
|
||||||
*/
|
*/
|
||||||
public static Symbol create(String elementName, Attributes attributes) throws IOException {
|
public static Symbol create(String elementName, Attributes attributes)
|
||||||
|
throws IOException {
|
||||||
String src = null;
|
String src = null;
|
||||||
|
|
||||||
for (int i = 0; i < attributes.getLength(); ++i) {
|
for (int i = 0; i < attributes.getLength(); ++i) {
|
||||||
@ -56,7 +57,8 @@ public final class Symbol implements RenderInstruction {
|
|||||||
|
|
||||||
private static void validate(String elementName, String src) {
|
private static void validate(String elementName, String src) {
|
||||||
if (src == null) {
|
if (src == null) {
|
||||||
throw new IllegalArgumentException("missing attribute src for element: " + elementName);
|
throw new IllegalArgumentException("missing attribute src for element: "
|
||||||
|
+ elementName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,14 +84,4 @@ public final class Symbol implements RenderInstruction {
|
|||||||
public void renderWay(IRenderCallback renderCallback, Tag[] tags) {
|
public void renderWay(IRenderCallback renderCallback, Tag[] tags) {
|
||||||
renderCallback.renderAreaSymbol(mBitmap);
|
renderCallback.renderAreaSymbol(mBitmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void scaleStrokeWidth(float scaleFactor) {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void scaleTextSize(float scaleFactor) {
|
|
||||||
// do nothing
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,6 +24,7 @@ import org.mapsforge.android.rendertheme.RenderTheme;
|
|||||||
import org.mapsforge.android.rendertheme.renderinstruction.Area;
|
import org.mapsforge.android.rendertheme.renderinstruction.Area;
|
||||||
import org.mapsforge.android.rendertheme.renderinstruction.Caption;
|
import org.mapsforge.android.rendertheme.renderinstruction.Caption;
|
||||||
import org.mapsforge.android.rendertheme.renderinstruction.Line;
|
import org.mapsforge.android.rendertheme.renderinstruction.Line;
|
||||||
|
import org.mapsforge.android.rendertheme.renderinstruction.PathText;
|
||||||
import org.mapsforge.core.Tag;
|
import org.mapsforge.core.Tag;
|
||||||
import org.mapsforge.core.Tile;
|
import org.mapsforge.core.Tile;
|
||||||
import org.mapsforge.database.IMapDatabase;
|
import org.mapsforge.database.IMapDatabase;
|
||||||
@ -414,24 +415,24 @@ public class MapGenerator implements IMapGenerator, IRenderCallback,
|
|||||||
private List<ShapeContainer> mCurLevelContainer2;
|
private List<ShapeContainer> mCurLevelContainer2;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void renderWay(Line line) {
|
public void renderWay(Line line, int level) {
|
||||||
List<ShapeContainer> c = mDrawingLayer.add(line.level, mWayDataContainer,
|
// List<ShapeContainer> c = mDrawingLayer.add(level, mWayDataContainer,
|
||||||
line.paint);
|
// line.paint);
|
||||||
|
//
|
||||||
if (mCurLevelContainer1 == null)
|
// if (mCurLevelContainer1 == null)
|
||||||
mCurLevelContainer1 = c;
|
// mCurLevelContainer1 = c;
|
||||||
else if (mCurLevelContainer2 == null)
|
// else if (mCurLevelContainer2 == null)
|
||||||
mCurLevelContainer2 = c;
|
// mCurLevelContainer2 = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void renderArea(Area area) {
|
public void renderArea(Area area, int level) {
|
||||||
if (area.paintFill != null)
|
// if (area.paintFill != null)
|
||||||
mCurLevelContainer1 = mDrawingLayer.add(area.level, mWayDataContainer,
|
// mCurLevelContainer1 = mDrawingLayer.add(level, mWayDataContainer,
|
||||||
area.paintFill);
|
// area.paintFill);
|
||||||
if (area.paintOutline != null)
|
// if (area.paintOutline != null)
|
||||||
mCurLevelContainer1 = mDrawingLayer.add(area.level, mWayDataContainer,
|
// mCurLevelContainer1 = mDrawingLayer.add(level, mWayDataContainer,
|
||||||
area.paintOutline);
|
// area.paintOutline);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -443,7 +444,7 @@ public class MapGenerator implements IMapGenerator, IRenderCallback,
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void renderWayText(String textKey, Paint paint, Paint outline) {
|
public void renderWayText(PathText pathText) {
|
||||||
// if (mWayDataContainer.textPos[0] >= 0)
|
// if (mWayDataContainer.textPos[0] >= 0)
|
||||||
// WayDecorator.renderText(this, paint, outline, mCoords, mWayDataContainer, mWayNames);
|
// WayDecorator.renderText(this, paint, outline, mCoords, mWayDataContainer, mWayNames);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,6 +33,7 @@ import org.mapsforge.android.mapgenerator.JobParameters;
|
|||||||
import org.mapsforge.android.mapgenerator.MapGeneratorJob;
|
import org.mapsforge.android.mapgenerator.MapGeneratorJob;
|
||||||
import org.mapsforge.android.mapgenerator.TileCacheKey;
|
import org.mapsforge.android.mapgenerator.TileCacheKey;
|
||||||
import org.mapsforge.android.mapgenerator.TileDistanceSort;
|
import org.mapsforge.android.mapgenerator.TileDistanceSort;
|
||||||
|
import org.mapsforge.android.rendertheme.RenderTheme;
|
||||||
import org.mapsforge.android.utils.GlUtils;
|
import org.mapsforge.android.utils.GlUtils;
|
||||||
import org.mapsforge.core.MapPosition;
|
import org.mapsforge.core.MapPosition;
|
||||||
import org.mapsforge.core.MercatorProjection;
|
import org.mapsforge.core.MercatorProjection;
|
||||||
@ -213,7 +214,7 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
|
|||||||
newTiles[tiles++] = tile;
|
newTiles[tiles++] = tile;
|
||||||
|
|
||||||
if (!tile.isReady || (tile.getScale() != scale)) {
|
if (!tile.isReady || (tile.getScale() != scale)) {
|
||||||
tile.isLoading = true;
|
// tile.isLoading = true;
|
||||||
// approximation for TileScheduler
|
// approximation for TileScheduler
|
||||||
if (tileY < tileTop || tileY > tileBottom || tileX < tileLeft
|
if (tileY < tileTop || tileY > tileBottom || tileX < tileLeft
|
||||||
|| tileX > tileRight)
|
|| tileX > tileRight)
|
||||||
@ -494,12 +495,6 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// FIXME
|
|
||||||
// if (loadedTexture) {
|
|
||||||
// synchronized (mMapWorker) {
|
|
||||||
// mMapWorker.notify();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -588,4 +583,10 @@ public class MapRenderer implements org.mapsforge.android.IMapRenderer {
|
|||||||
public IMapGenerator createMapGenerator() {
|
public IMapGenerator createMapGenerator() {
|
||||||
return new MapGenerator();
|
return new MapGenerator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRenderTheme(RenderTheme t) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,7 +38,8 @@ final class WayDecorator {
|
|||||||
*/
|
*/
|
||||||
private static final int SEGMENT_SAFETY_DISTANCE = 30;
|
private static final int SEGMENT_SAFETY_DISTANCE = 30;
|
||||||
|
|
||||||
static void renderSymbol(Bitmap symbolBitmap, boolean alignCenter, boolean repeatSymbol, float[][] coordinates,
|
static void renderSymbol(Bitmap symbolBitmap, boolean alignCenter,
|
||||||
|
boolean repeatSymbol, float[][] coordinates,
|
||||||
List<SymbolContainer> waySymbols) {
|
List<SymbolContainer> waySymbols) {
|
||||||
int skipPixels = SEGMENT_SAFETY_DISTANCE;
|
int skipPixels = SEGMENT_SAFETY_DISTANCE;
|
||||||
|
|
||||||
@ -68,9 +69,11 @@ final class WayDecorator {
|
|||||||
// move the previous point forward towards the current point
|
// move the previous point forward towards the current point
|
||||||
previousX += diffX * segmentSkipPercentage;
|
previousX += diffX * segmentSkipPercentage;
|
||||||
previousY += diffY * segmentSkipPercentage;
|
previousY += diffY * segmentSkipPercentage;
|
||||||
symbolAngle = (float) Math.toDegrees(Math.atan2(currentY - previousY, currentX - previousX));
|
symbolAngle = (float) Math.toDegrees(Math.atan2(currentY - previousY,
|
||||||
|
currentX - previousX));
|
||||||
|
|
||||||
waySymbols.add(new SymbolContainer(symbolBitmap, previousX, previousY, alignCenter, symbolAngle));
|
waySymbols.add(new SymbolContainer(symbolBitmap, previousX, previousY,
|
||||||
|
alignCenter, symbolAngle));
|
||||||
|
|
||||||
// check if the symbol should only be rendered once
|
// check if the symbol should only be rendered once
|
||||||
if (!repeatSymbol) {
|
if (!repeatSymbol) {
|
||||||
@ -145,7 +148,8 @@ final class WayDecorator {
|
|||||||
} else if ((currentY - nextY) == 0)
|
} else if ((currentY - nextY) == 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
float diff = ((float) (diffX) / (diffY) - (float) (currentX - nextX) / (currentY - nextY));
|
float diff = ((float) (diffX) / (diffY) - (float) (currentX - nextX)
|
||||||
|
/ (currentY - nextY));
|
||||||
|
|
||||||
// skip segments with corners
|
// skip segments with corners
|
||||||
if (diff >= 0.2 || diff <= -0.2)
|
if (diff >= 0.2 || diff <= -0.2)
|
||||||
@ -210,7 +214,7 @@ final class WayDecorator {
|
|||||||
y2 = previousY;
|
y2 = previousY;
|
||||||
}
|
}
|
||||||
|
|
||||||
// estimate position of test on path
|
// estimate position of text on path
|
||||||
width = (x2 - x1) / 2;
|
width = (x2 - x1) / 2;
|
||||||
x2 = x2 - (int) (width - s * width);
|
x2 = x2 - (int) (width - s * width);
|
||||||
x1 = x1 + (int) (width - s * width);
|
x1 = x1 + (int) (width - s * width);
|
||||||
@ -234,7 +238,8 @@ final class WayDecorator {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
// check crossings
|
// check crossings
|
||||||
if (GeometryUtils.lineIntersect(x1, y1, x2, y2, wtc2.x1, wtc2.y1, wtc2.x2, wtc2.y2)) {
|
if (GeometryUtils.lineIntersect(x1, y1, x2, y2, wtc2.x1, wtc2.y1,
|
||||||
|
wtc2.x2, wtc2.y2)) {
|
||||||
intersects = true;
|
intersects = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -244,7 +249,8 @@ final class WayDecorator {
|
|||||||
short top2 = (wtc2.y1 < wtc2.y2 ? wtc2.y1 : wtc2.y2);
|
short top2 = (wtc2.y1 < wtc2.y2 ? wtc2.y1 : wtc2.y2);
|
||||||
short bot2 = (wtc2.y1 < wtc2.y2 ? wtc2.y2 : wtc2.y1);
|
short bot2 = (wtc2.y1 < wtc2.y2 ? wtc2.y2 : wtc2.y1);
|
||||||
|
|
||||||
if (x1 - 10 < wtc2.x2 && wtc2.x1 - 10 < x2 && top - 10 < bot2 && top2 - 10 < bot) {
|
if (x1 - 10 < wtc2.x2 && wtc2.x1 - 10 < x2 && top - 10 < bot2
|
||||||
|
&& top2 - 10 < bot) {
|
||||||
|
|
||||||
if (wtc2.text.equals(text)) {
|
if (wtc2.text.equals(text)) {
|
||||||
intersects = true;
|
intersects = true;
|
||||||
@ -260,7 +266,8 @@ final class WayDecorator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Log.d("mapsforge", "add " + text + " " + first + " " + last);
|
Log.d("mapsforge", "add " + text + " " + first + " " + last);
|
||||||
WayTextContainer wtc = new WayTextContainer(first, last, wayDataContainer, text,
|
WayTextContainer wtc = new WayTextContainer(first, last,
|
||||||
|
wayDataContainer, text,
|
||||||
paint);
|
paint);
|
||||||
wtc.x1 = (short) x1;
|
wtc.x1 = (short) x1;
|
||||||
wtc.y1 = (short) y1;
|
wtc.y1 = (short) y1;
|
||||||
@ -272,7 +279,8 @@ final class WayDecorator {
|
|||||||
containerSize++;
|
containerSize++;
|
||||||
|
|
||||||
if (outline != null) {
|
if (outline != null) {
|
||||||
wayNames.add(new WayTextContainer(first, last, wayDataContainer, text, outline));
|
wayNames.add(new WayTextContainer(first, last, wayDataContainer,
|
||||||
|
text, outline));
|
||||||
containerSize++;
|
containerSize++;
|
||||||
}
|
}
|
||||||
// 500 ??? how big is a tile?!
|
// 500 ??? how big is a tile?!
|
||||||
|
|||||||
@ -29,7 +29,7 @@ public class GlConfigChooser implements GLSurfaceView.EGLConfigChooser {
|
|||||||
EGL10.EGL_GREEN_SIZE, 6,
|
EGL10.EGL_GREEN_SIZE, 6,
|
||||||
EGL10.EGL_BLUE_SIZE, 5,
|
EGL10.EGL_BLUE_SIZE, 5,
|
||||||
EGL10.EGL_ALPHA_SIZE, 0,
|
EGL10.EGL_ALPHA_SIZE, 0,
|
||||||
EGL10.EGL_DEPTH_SIZE, 0,
|
EGL10.EGL_DEPTH_SIZE, 16,
|
||||||
// Requires that setEGLContextClientVersion(2) is called on the view.
|
// Requires that setEGLContextClientVersion(2) is called on the view.
|
||||||
EGL10.EGL_RENDERABLE_TYPE, 4 /* EGL_OPENGL_ES2_BIT */,
|
EGL10.EGL_RENDERABLE_TYPE, 4 /* EGL_OPENGL_ES2_BIT */,
|
||||||
// EGL10.EGL_SAMPLE_BUFFERS, 1 /* true */,
|
// EGL10.EGL_SAMPLE_BUFFERS, 1 /* true */,
|
||||||
@ -50,7 +50,7 @@ public class GlConfigChooser implements GLSurfaceView.EGLConfigChooser {
|
|||||||
EGL10.EGL_GREEN_SIZE, 6,
|
EGL10.EGL_GREEN_SIZE, 6,
|
||||||
EGL10.EGL_BLUE_SIZE, 5,
|
EGL10.EGL_BLUE_SIZE, 5,
|
||||||
EGL10.EGL_ALPHA_SIZE, 0,
|
EGL10.EGL_ALPHA_SIZE, 0,
|
||||||
EGL10.EGL_DEPTH_SIZE, 0,
|
EGL10.EGL_DEPTH_SIZE, 16,
|
||||||
EGL10.EGL_RENDERABLE_TYPE, 4 /* EGL_OPENGL_ES2_BIT */,
|
EGL10.EGL_RENDERABLE_TYPE, 4 /* EGL_OPENGL_ES2_BIT */,
|
||||||
EGL10.EGL_STENCIL_SIZE, 4,
|
EGL10.EGL_STENCIL_SIZE, 4,
|
||||||
EGL10.EGL_NONE };
|
EGL10.EGL_NONE };
|
||||||
@ -93,7 +93,10 @@ public class GlConfigChooser implements GLSurfaceView.EGLConfigChooser {
|
|||||||
// // else
|
// // else
|
||||||
// if (findConfigAttrib(egl, display, configs[i], EGL10.EGL_RED_SIZE, 0) == 5
|
// if (findConfigAttrib(egl, display, configs[i], EGL10.EGL_RED_SIZE, 0) == 5
|
||||||
// &&
|
// &&
|
||||||
// findConfigAttrib(egl, display, configs[i], EGL10.EGL_ALPHA_SIZE, 0) == 0) {
|
// findConfigAttrib(egl, display, configs[i], EGL10.EGL_ALPHA_SIZE, 0) == 0
|
||||||
|
// // &&
|
||||||
|
// // findConfigAttrib(egl, display, configs[i], EGL10.EGL_DEPTH_SIZE, 0) == 16
|
||||||
|
// ) {
|
||||||
// index = i;
|
// index = i;
|
||||||
// break;
|
// break;
|
||||||
// }
|
// }
|
||||||
|
|||||||
@ -92,9 +92,23 @@ public class Tag {
|
|||||||
this.hashCodeValue = calculateHashCode();
|
this.hashCodeValue = calculateHashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param key
|
||||||
|
* the key of the tag.
|
||||||
|
* @param value
|
||||||
|
* the value of the tag.
|
||||||
|
* @param intern
|
||||||
|
* true when string should be intern()alized.
|
||||||
|
*/
|
||||||
public Tag(String key, String value, boolean intern) {
|
public Tag(String key, String value, boolean intern) {
|
||||||
this.key = (key == null ? null : key);
|
if (intern) {
|
||||||
this.value = (value == null ? null : value);
|
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();
|
this.hashCodeValue = calculateHashCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -60,6 +60,8 @@ public class Tile {
|
|||||||
*/
|
*/
|
||||||
public final long pixelY;
|
public final long pixelY;
|
||||||
|
|
||||||
|
public volatile boolean isCanceled;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param tileX
|
* @param tileX
|
||||||
* the X number of the tile.
|
* the X number of the tile.
|
||||||
|
|||||||
@ -251,7 +251,7 @@ public class MapDatabase implements IMapDatabase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getMapProjection() {
|
public String getMapProjection() {
|
||||||
return getMapFileInfo().projectionName;
|
return "WSG84"; // getMapFileInfo().projectionName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -883,14 +883,25 @@ public class MapDatabase implements IMapDatabase {
|
|||||||
boolean featureWayDoubleDeltaEncoding = (featureByte & WAY_FEATURE_DOUBLE_DELTA_ENCODING) != 0;
|
boolean featureWayDoubleDeltaEncoding = (featureByte & WAY_FEATURE_DOUBLE_DELTA_ENCODING) != 0;
|
||||||
|
|
||||||
// check if the way has a name
|
// check if the way has a name
|
||||||
if ((featureByte & WAY_FEATURE_NAME) != 0)
|
if ((featureByte & WAY_FEATURE_NAME) != 0) {
|
||||||
textPos[0] = mReadBuffer.readUnsignedInt();
|
textPos[0] = mReadBuffer.readUnsignedInt();
|
||||||
|
String str = mReadBuffer.readUTF8EncodedStringAt(stringOffset
|
||||||
|
+ textPos[0]);
|
||||||
|
if (changed) {
|
||||||
|
Tag[] tmp = tags;
|
||||||
|
tags = new Tag[tmp.length + 1];
|
||||||
|
System.arraycopy(tmp, 0, tags, 0, tmp.length);
|
||||||
|
}
|
||||||
|
tags[tags.length - 1] = new Tag("name", str, false);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
textPos[0] = -1;
|
textPos[0] = -1;
|
||||||
|
|
||||||
// check if the way has a house number
|
// check if the way has a house number
|
||||||
if ((featureByte & WAY_FEATURE_HOUSE_NUMBER) != 0)
|
if ((featureByte & WAY_FEATURE_HOUSE_NUMBER) != 0) {
|
||||||
textPos[1] = mReadBuffer.readUnsignedInt();
|
textPos[1] = mReadBuffer.readUnsignedInt();
|
||||||
|
|
||||||
|
}
|
||||||
else
|
else
|
||||||
textPos[1] = -1;
|
textPos[1] = -1;
|
||||||
|
|
||||||
|
|||||||
@ -19,10 +19,10 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.SocketException;
|
import java.net.SocketException;
|
||||||
import java.net.SocketTimeoutException;
|
import java.net.SocketTimeoutException;
|
||||||
import java.util.HashMap;
|
import java.util.Collections;
|
||||||
import java.util.zip.GZIPInputStream;
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.http.Header;
|
|
||||||
import org.apache.http.HttpEntity;
|
import org.apache.http.HttpEntity;
|
||||||
import org.apache.http.HttpResponse;
|
import org.apache.http.HttpResponse;
|
||||||
import org.apache.http.HttpStatus;
|
import org.apache.http.HttpStatus;
|
||||||
@ -33,7 +33,6 @@ import org.apache.http.conn.scheme.PlainSocketFactory;
|
|||||||
import org.apache.http.conn.scheme.Scheme;
|
import org.apache.http.conn.scheme.Scheme;
|
||||||
import org.apache.http.conn.scheme.SchemeRegistry;
|
import org.apache.http.conn.scheme.SchemeRegistry;
|
||||||
import org.apache.http.impl.client.DefaultHttpClient;
|
import org.apache.http.impl.client.DefaultHttpClient;
|
||||||
import org.apache.http.message.BasicHeader;
|
|
||||||
import org.apache.http.params.BasicHttpParams;
|
import org.apache.http.params.BasicHttpParams;
|
||||||
import org.apache.http.params.HttpConnectionParams;
|
import org.apache.http.params.HttpConnectionParams;
|
||||||
import org.apache.http.params.HttpParams;
|
import org.apache.http.params.HttpParams;
|
||||||
@ -41,7 +40,6 @@ import org.mapsforge.core.BoundingBox;
|
|||||||
import org.mapsforge.core.GeoPoint;
|
import org.mapsforge.core.GeoPoint;
|
||||||
import org.mapsforge.core.Tag;
|
import org.mapsforge.core.Tag;
|
||||||
import org.mapsforge.core.Tile;
|
import org.mapsforge.core.Tile;
|
||||||
import org.mapsforge.core.WebMercator;
|
|
||||||
import org.mapsforge.database.FileOpenResult;
|
import org.mapsforge.database.FileOpenResult;
|
||||||
import org.mapsforge.database.IMapDatabase;
|
import org.mapsforge.database.IMapDatabase;
|
||||||
import org.mapsforge.database.IMapDatabaseCallback;
|
import org.mapsforge.database.IMapDatabaseCallback;
|
||||||
@ -60,45 +58,62 @@ public class MapDatabase implements IMapDatabase {
|
|||||||
private static final MapFileInfo mMapInfo =
|
private static final MapFileInfo mMapInfo =
|
||||||
new MapFileInfo(new BoundingBox(-180, -90, 180, 90),
|
new MapFileInfo(new BoundingBox(-180, -90, 180, 90),
|
||||||
new Byte((byte) 4), new GeoPoint(53.11, 8.85),
|
new Byte((byte) 4), new GeoPoint(53.11, 8.85),
|
||||||
WebMercator.NAME, 0, 0, 0, "de", "comment", "author");
|
null, 0, 0, 0, "de", "comment", "author");
|
||||||
|
|
||||||
private boolean mOpenFile = false;
|
private boolean mOpenFile = false;
|
||||||
|
|
||||||
// private static final String URL = "http://city.informatik.uni-bremen.de:8020/test/%d/%d/%d.osmtile";
|
// private static final String URL = "http://city.informatik.uni-bremen.de:8020/test/%d/%d/%d.osmtile";
|
||||||
private static final String URL = "http://city.informatik.uni-bremen.de/osmstache/test/%d/%d/%d.osmtile";
|
private static final String URL = "http://city.informatik.uni-bremen.de/osmstache/test/%d/%d/%d.osmtile";
|
||||||
// private static final String URL = "http://city.informatik.uni-bremen.de/osmstache/gis2/%d/%d/%d.osmtile";
|
// private static final String URL = "http://city.informatik.uni-bremen.de/osmstache/gis2/%d/%d/%d.osmtile";
|
||||||
private static final Header encodingHeader =
|
// private static final Header encodingHeader =
|
||||||
new BasicHeader("Accept-Encoding", "gzip");
|
// new BasicHeader("Accept-Encoding", "gzip");
|
||||||
|
|
||||||
private static volatile HashMap<String, Tag> tagHash = new HashMap<String, Tag>(100);
|
private static final int MAX_TAGS_CACHE = 100;
|
||||||
|
private static Map<String, Tag> tagHash = Collections
|
||||||
|
.synchronizedMap(new LinkedHashMap<String, Tag>(
|
||||||
|
MAX_TAGS_CACHE, 0.75f, true) {
|
||||||
|
|
||||||
private Tag[] curTags = new Tag[250];
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean removeEldestEntry(Entry<String, Tag> e) {
|
||||||
|
if (size() < MAX_TAGS_CACHE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Log.d(TAG, "cache: drop " + e.getValue());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
private final static float REF_TILE_SIZE = 4096.0f;
|
||||||
|
|
||||||
|
private int MAX_TILE_TAGS = 100;
|
||||||
|
private Tag[] curTags = new Tag[MAX_TILE_TAGS];
|
||||||
private int mCurTagCnt;
|
private int mCurTagCnt;
|
||||||
|
|
||||||
private HttpClient mClient;
|
private HttpClient mClient;
|
||||||
private IMapDatabaseCallback mMapGenerator;
|
private IMapDatabaseCallback mMapGenerator;
|
||||||
private float mScaleFactor;
|
private float mScaleFactor;
|
||||||
private HttpGet mRequest = null;
|
private HttpGet mRequest = null;
|
||||||
|
private Tile mTile;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public QueryResult executeQuery(Tile tile, IMapDatabaseCallback mapDatabaseCallback) {
|
public QueryResult executeQuery(Tile tile, IMapDatabaseCallback mapDatabaseCallback) {
|
||||||
mCanceled = false;
|
mCanceled = false;
|
||||||
|
// just used for debugging ....
|
||||||
|
mTile = tile;
|
||||||
// Log.d(TAG, "get tile >> : " + tile);
|
// Log.d(TAG, "get tile >> : " + tile);
|
||||||
|
|
||||||
String url = String.format(URL, Integer.valueOf(tile.zoomLevel),
|
String url = String.format(URL, Integer.valueOf(tile.zoomLevel),
|
||||||
Long.valueOf(tile.tileX), Long.valueOf(tile.tileY));
|
Long.valueOf(tile.tileX), Long.valueOf(tile.tileY));
|
||||||
|
|
||||||
HttpGet getRequest = new HttpGet(url);
|
HttpGet getRequest = new HttpGet(url);
|
||||||
getRequest.addHeader(encodingHeader);
|
|
||||||
|
|
||||||
mRequest = getRequest;
|
mRequest = getRequest;
|
||||||
mMapGenerator = mapDatabaseCallback;
|
mMapGenerator = mapDatabaseCallback;
|
||||||
mCurTagCnt = 0;
|
mCurTagCnt = 0;
|
||||||
|
|
||||||
// using variable coordinate scalefactor to take advantage of varint
|
mScaleFactor = REF_TILE_SIZE / Tile.TILE_SIZE;
|
||||||
mScaleFactor = 1 / 100f;
|
|
||||||
if (tile.zoomLevel < 12)
|
|
||||||
mScaleFactor = (float) Math.pow(2, (12 - tile.zoomLevel)) / 100f;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
HttpResponse response = mClient.execute(getRequest);
|
HttpResponse response = mClient.execute(getRequest);
|
||||||
@ -110,17 +125,24 @@ public class MapDatabase implements IMapDatabase {
|
|||||||
entity.consumeContent();
|
entity.consumeContent();
|
||||||
return QueryResult.FAILED;
|
return QueryResult.FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mTile.isCanceled) {
|
||||||
|
Log.d(TAG, "1 loading canceled " + mTile);
|
||||||
|
entity.consumeContent();
|
||||||
|
return QueryResult.FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
InputStream is = null;
|
InputStream is = null;
|
||||||
GZIPInputStream zis = null;
|
// GZIPInputStream zis = null;
|
||||||
try {
|
try {
|
||||||
is = entity.getContent();
|
is = entity.getContent();
|
||||||
zis = new GZIPInputStream(is);
|
// zis = new GZIPInputStream(is);
|
||||||
|
|
||||||
decode(zis);
|
decode(is);
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
if (zis != null)
|
// if (zis != null)
|
||||||
zis.close();
|
// zis.close();
|
||||||
if (is != null)
|
if (is != null)
|
||||||
is.close();
|
is.close();
|
||||||
entity.consumeContent();
|
entity.consumeContent();
|
||||||
@ -137,6 +159,12 @@ public class MapDatabase implements IMapDatabase {
|
|||||||
return QueryResult.FAILED;
|
return QueryResult.FAILED;
|
||||||
}
|
}
|
||||||
mRequest = null;
|
mRequest = null;
|
||||||
|
|
||||||
|
if (mTile.isCanceled) {
|
||||||
|
Log.d(TAG, "2 loading canceled " + mTile);
|
||||||
|
return QueryResult.FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
// Log.d(TAG, "get tile << : " + tile);
|
// Log.d(TAG, "get tile << : " + tile);
|
||||||
|
|
||||||
return QueryResult.SUCCESS;
|
return QueryResult.SUCCESS;
|
||||||
@ -144,7 +172,7 @@ public class MapDatabase implements IMapDatabase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getMapProjection() {
|
public String getMapProjection() {
|
||||||
return WebMercator.NAME;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -158,8 +186,6 @@ public class MapDatabase implements IMapDatabase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void createClient() {
|
private void createClient() {
|
||||||
// mClient = AndroidHttpClient.newInstance("Android");
|
|
||||||
|
|
||||||
mOpenFile = true;
|
mOpenFile = true;
|
||||||
HttpParams params = new BasicHttpParams();
|
HttpParams params = new BasicHttpParams();
|
||||||
HttpConnectionParams.setStaleCheckingEnabled(params, false);
|
HttpConnectionParams.setStaleCheckingEnabled(params, false);
|
||||||
@ -193,7 +219,8 @@ public class MapDatabase implements IMapDatabase {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final int BUFFER_SIZE = 65536 * 2;
|
// // // hand sewed tile protocol buffers decoder // // //
|
||||||
|
private static final int BUFFER_SIZE = 65536;
|
||||||
|
|
||||||
private final byte[] buffer = new byte[BUFFER_SIZE];
|
private final byte[] buffer = new byte[BUFFER_SIZE];
|
||||||
private int bufferPos;
|
private int bufferPos;
|
||||||
@ -261,20 +288,25 @@ public class MapDatabase implements IMapDatabase {
|
|||||||
String tagString = decodeString();
|
String tagString = decodeString();
|
||||||
|
|
||||||
Tag tag = tagHash.get(tagString);
|
Tag tag = tagHash.get(tagString);
|
||||||
|
|
||||||
if (tag == null) {
|
if (tag == null) {
|
||||||
// Log.d(TAG, "tag:" + tagString);
|
if (tagString.startsWith(Tag.TAG_KEY_NAME))
|
||||||
if (tagString.equals("name="))
|
tag = new Tag(Tag.TAG_KEY_NAME, tagString.substring(5), false);
|
||||||
tag = new Tag(tagString, false);
|
|
||||||
else
|
else
|
||||||
tag = new Tag(tagString);
|
tag = new Tag(tagString);
|
||||||
|
|
||||||
tagHash.put(tagString, tag);
|
tagHash.put(tagString, tag);
|
||||||
}
|
}
|
||||||
// FIXME ...
|
|
||||||
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -285,7 +317,7 @@ public class MapDatabase implements IMapDatabase {
|
|||||||
int indexCnt = 0;
|
int indexCnt = 0;
|
||||||
int tagCnt = 0;
|
int tagCnt = 0;
|
||||||
int coordCnt = 0;
|
int coordCnt = 0;
|
||||||
int layer = 0;
|
int layer = 5;
|
||||||
Tag[] tags = null;
|
Tag[] tags = null;
|
||||||
short[] index = null;
|
short[] index = null;
|
||||||
|
|
||||||
@ -294,7 +326,6 @@ public class MapDatabase implements IMapDatabase {
|
|||||||
|
|
||||||
while (bytesRead < end) {
|
while (bytesRead < end) {
|
||||||
// read tag and wire type
|
// read tag and wire type
|
||||||
|
|
||||||
int val = decodeVarint32();
|
int val = decodeVarint32();
|
||||||
if (val == 0)
|
if (val == 0)
|
||||||
break;
|
break;
|
||||||
@ -350,18 +381,10 @@ public class MapDatabase implements IMapDatabase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
float[] coords = tmpCoords;
|
float[] coords = tmpCoords;
|
||||||
int pos = 0;
|
|
||||||
|
|
||||||
float z = mScaleFactor;
|
// FIXME !!!!!
|
||||||
for (int j = 0, m = indexCnt; j < m; j++) {
|
if (layer == 0)
|
||||||
float lastX = 0;
|
layer = 5;
|
||||||
float lastY = 0;
|
|
||||||
|
|
||||||
for (int n = index[j] + pos; pos < n; pos += 2) {
|
|
||||||
lastX = coords[pos] = (coords[pos] * z) + lastX;
|
|
||||||
lastY = coords[pos + 1] = (coords[pos + 1] * z) + lastY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mMapGenerator.renderWay((byte) layer, tags, coords, index, polygon);
|
mMapGenerator.renderWay((byte) layer, tags, coords, index, polygon);
|
||||||
return true;
|
return true;
|
||||||
@ -429,12 +452,20 @@ public class MapDatabase implements IMapDatabase {
|
|||||||
readBuffer(bytes);
|
readBuffer(bytes);
|
||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
int end = bufferPos + bytes;
|
int end = bufferPos + bytes;
|
||||||
|
float scale = mScaleFactor;
|
||||||
// read repeated sint32
|
// read repeated sint32
|
||||||
|
int lastX = 0;
|
||||||
|
int lastY = 0;
|
||||||
while (bufferPos < end && cnt < numNodes) {
|
while (bufferPos < end && cnt < numNodes) {
|
||||||
float lon = decodeZigZag32(decodeVarint32()) * mScaleFactor;
|
int lon = decodeZigZag32(decodeVarint32()); // * mScaleFactor;
|
||||||
float lat = decodeZigZag32(decodeVarint32()) * mScaleFactor;
|
int lat = decodeZigZag32(decodeVarint32()); // * mScaleFactor;
|
||||||
mMapGenerator.renderPointOfInterest(layer, lat, lon, tags);
|
lastX = lon + lastX;
|
||||||
|
lastY = lat + lastY;
|
||||||
|
|
||||||
|
mMapGenerator.renderPointOfInterest(layer,
|
||||||
|
lastY / scale,
|
||||||
|
lastX / scale,
|
||||||
|
tags);
|
||||||
cnt += 2;
|
cnt += 2;
|
||||||
}
|
}
|
||||||
return cnt;
|
return cnt;
|
||||||
@ -443,13 +474,6 @@ public class MapDatabase implements IMapDatabase {
|
|||||||
private int MAX_WAY_COORDS = 32768;
|
private int MAX_WAY_COORDS = 32768;
|
||||||
private float[] tmpCoords = new float[MAX_WAY_COORDS];
|
private float[] tmpCoords = new float[MAX_WAY_COORDS];
|
||||||
|
|
||||||
// private boolean ensureBufferSize(int size) throws IOException {
|
|
||||||
// if (size > (bufferSize - bufferPos))
|
|
||||||
// readBuffer(size - (bufferSize - bufferPos));
|
|
||||||
//
|
|
||||||
// return true;
|
|
||||||
// }
|
|
||||||
|
|
||||||
private Tag[] decodeWayTags(int tagCnt) throws IOException {
|
private Tag[] decodeWayTags(int tagCnt) throws IOException {
|
||||||
int bytes = decodeVarint32();
|
int bytes = decodeVarint32();
|
||||||
|
|
||||||
@ -457,33 +481,45 @@ public class MapDatabase implements IMapDatabase {
|
|||||||
|
|
||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
int end = bytesRead + bytes;
|
int end = bytesRead + bytes;
|
||||||
int max = curTags.length;
|
int max = mCurTagCnt;
|
||||||
|
|
||||||
while (bytesRead < end) {
|
while (bytesRead < end) {
|
||||||
int tagNum = decodeVarint32();
|
int tagNum = decodeVarint32();
|
||||||
|
|
||||||
if (tagNum < 0 || cnt == tagCnt)
|
if (tagNum < 0 || cnt == tagCnt) {
|
||||||
continue;
|
Log.d(TAG, "NULL TAG: " + mTile + " invalid tag:" + tagNum + " "
|
||||||
|
+ tagCnt + "/" + cnt);
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (tagNum < Tags.MAX)
|
if (tagNum < Tags.MAX)
|
||||||
tags[cnt++] = Tags.tags[tagNum];
|
tags[cnt++] = Tags.tags[tagNum];
|
||||||
else {
|
else {
|
||||||
tagNum -= Tags.LIMIT;
|
tagNum -= Tags.LIMIT;
|
||||||
|
|
||||||
if (tagNum >= 0 && tagNum < max) {
|
if (tagNum >= 0 && tagNum < max) {
|
||||||
// Log.d(TAG, "variable tag: " + curTags[tagNum]);
|
// Log.d(TAG, "variable tag: " + curTags[tagNum]);
|
||||||
tags[cnt++] = curTags[tagNum];
|
tags[cnt++] = curTags[tagNum];
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "NULL TAG: " + mTile + " could find tag:" + tagNum + " "
|
||||||
|
+ tagCnt + "/" + cnt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// else DEBUG...
|
|
||||||
}
|
}
|
||||||
|
if (tagCnt != cnt)
|
||||||
|
Log.d(TAG, "NULL TAG: " + mTile + " ...");
|
||||||
|
|
||||||
return tags;
|
return tags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private short[] mIndices = new short[10];
|
||||||
|
|
||||||
private short[] decodeWayIndices(int indexCnt) throws IOException {
|
private short[] decodeWayIndices(int indexCnt) throws IOException {
|
||||||
int bytes = decodeVarint32();
|
int bytes = decodeVarint32();
|
||||||
|
|
||||||
short[] index = new short[indexCnt];
|
short[] index = mIndices;
|
||||||
|
if (index.length < indexCnt + 1) {
|
||||||
|
index = mIndices = new short[indexCnt + 1];
|
||||||
|
}
|
||||||
|
|
||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
int end = bytesRead + bytes;
|
int end = bytesRead + bytes;
|
||||||
@ -495,6 +531,9 @@ public class MapDatabase implements IMapDatabase {
|
|||||||
// else DEBUG...
|
// else DEBUG...
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
index[indexCnt] = -1;
|
||||||
|
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -514,67 +553,78 @@ public class MapDatabase implements IMapDatabase {
|
|||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
|
int x, lastX = 0;
|
||||||
|
int y, lastY = 0;
|
||||||
|
boolean even = true;
|
||||||
|
|
||||||
|
float scale = mScaleFactor;
|
||||||
|
|
||||||
// read repeated sint32
|
// read repeated sint32
|
||||||
while (pos < end) {
|
while (pos < end) {
|
||||||
if (cnt >= MAX_WAY_COORDS) {
|
if (cnt >= MAX_WAY_COORDS) {
|
||||||
|
Log.d(TAG, "increase way coord buffer " + mTile);
|
||||||
|
|
||||||
MAX_WAY_COORDS += 128;
|
MAX_WAY_COORDS += 128;
|
||||||
float[] tmp = new float[MAX_WAY_COORDS];
|
float[] tmp = new float[MAX_WAY_COORDS];
|
||||||
System.arraycopy(coords, 0, tmp, 0, cnt);
|
System.arraycopy(coords, 0, tmp, 0, cnt);
|
||||||
tmpCoords = coords = tmp;
|
tmpCoords = coords = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
byte tmp = buf[pos++];
|
if (buf[pos] >= 0) {
|
||||||
if (tmp >= 0) {
|
result = buf[pos++];
|
||||||
result = tmp;
|
} else if (buf[pos + 1] >= 0) {
|
||||||
|
result = buf[pos] & 0x7f
|
||||||
|
| buf[pos + 1] << 7;
|
||||||
|
pos += 2;
|
||||||
|
} else if (buf[pos + 2] >= 0) {
|
||||||
|
result = buf[pos] & 0x7f
|
||||||
|
| buf[pos + 1] << 7
|
||||||
|
| buf[pos + 2] << 14;
|
||||||
|
pos += 3;
|
||||||
|
} else if (buf[pos + 3] >= 0) {
|
||||||
|
result = buf[pos] & 0x7f
|
||||||
|
| buf[pos + 1] << 7
|
||||||
|
| buf[pos + 2] << 14
|
||||||
|
| buf[pos + 3] << 21;
|
||||||
|
pos += 4;
|
||||||
|
Log.d(TAG, "4 Stuffs too large " + mTile);
|
||||||
} else {
|
} else {
|
||||||
result = tmp & 0x7f;
|
result = buf[pos] & 0x7f
|
||||||
if ((tmp = buf[pos++]) >= 0) {
|
| buf[pos + 1] << 7
|
||||||
result |= tmp << 7;
|
| buf[pos + 2] << 14
|
||||||
} else {
|
| buf[pos + 3] << 21
|
||||||
result |= (tmp & 0x7f) << 7;
|
| buf[pos + 4] << 28;
|
||||||
if ((tmp = buf[pos++]) >= 0) {
|
pos += 5;
|
||||||
result |= tmp << 14;
|
|
||||||
} else {
|
|
||||||
result |= (tmp & 0x7f) << 14;
|
|
||||||
if ((tmp = buf[pos++]) >= 0) {
|
|
||||||
result |= tmp << 21;
|
|
||||||
} else {
|
|
||||||
result |= (tmp & 0x7f) << 21;
|
|
||||||
result |= (tmp = buf[pos++]) << 28;
|
|
||||||
|
|
||||||
if (tmp < 0) {
|
Log.d(TAG, "5 Stuffs too large " + mTile);
|
||||||
int i = 0;
|
|
||||||
// Discard upper 32 bits.
|
|
||||||
while (i++ < 5) {
|
|
||||||
if (buf[pos++] >= 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == 5)
|
if (buf[pos + 4] < 0) {
|
||||||
// FIXME throw some poo
|
Log.d(TAG, "Stuffs too large ...");
|
||||||
Log.d(TAG, "EEK malformedVarint");
|
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;
|
bufferPos = pos;
|
||||||
bytesRead += bytes;
|
bytesRead += bytes;
|
||||||
|
|
||||||
// while (bytesRead < end) {
|
|
||||||
// int val = decodeZigZag32(decodeVarint32());
|
|
||||||
// if (cnt >= MAX_WAY_COORDS) {
|
|
||||||
// MAX_WAY_COORDS += 128;
|
|
||||||
// Log.d(TAG, "increase coords array " + MAX_WAY_COORDS);
|
|
||||||
// float[] tmp = new float[MAX_WAY_COORDS];
|
|
||||||
// System.arraycopy(tmpCoords, 0, tmp, 0, cnt);
|
|
||||||
// tmpCoords = tmp;
|
|
||||||
// }
|
|
||||||
// tmpCoords[cnt++] = val;
|
|
||||||
// }
|
|
||||||
return cnt;
|
return cnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -589,9 +639,6 @@ public class MapDatabase implements IMapDatabase {
|
|||||||
}
|
}
|
||||||
bufferSize = len;
|
bufferSize = len;
|
||||||
bufferPos = 0;
|
bufferPos = 0;
|
||||||
|
|
||||||
// Log.d(TAG, "pos " + bufferPos + ", size " + bufferSize + ", read "
|
|
||||||
// + bytesRead);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readBuffer(int size) throws IOException {
|
private void readBuffer(int size) throws IOException {
|
||||||
@ -612,6 +659,10 @@ public class MapDatabase implements IMapDatabase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
while ((bufferSize - bufferPos) < size) {
|
while ((bufferSize - bufferPos) < size) {
|
||||||
|
if (mTile.isCanceled) {
|
||||||
|
throw new IOException("canceled " + mTile);
|
||||||
|
}
|
||||||
|
|
||||||
// read until requested size is available in buffer
|
// read until requested size is available in buffer
|
||||||
int len = inputStream.read(buffer, bufferSize, BUFFER_SIZE - bufferSize);
|
int len = inputStream.read(buffer, bufferSize, BUFFER_SIZE - bufferSize);
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
@ -621,13 +672,6 @@ public class MapDatabase implements IMapDatabase {
|
|||||||
|
|
||||||
bufferSize += len;
|
bufferSize += len;
|
||||||
|
|
||||||
// if (len == 0)
|
|
||||||
// try {
|
|
||||||
// wait(50);
|
|
||||||
// } catch (InterruptedException e) {
|
|
||||||
// // just waiting for data
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (mCanceled)
|
if (mCanceled)
|
||||||
throw new IOException("... canceld?");
|
throw new IOException("... canceld?");
|
||||||
}
|
}
|
||||||
@ -637,6 +681,17 @@ public class MapDatabase implements IMapDatabase {
|
|||||||
// + ", read " + bytesRead);
|
// + ", read " + bytesRead);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean mCanceled;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void cancel() {
|
||||||
|
mCanceled = true;
|
||||||
|
if (mRequest != null) {
|
||||||
|
mRequest.abort();
|
||||||
|
mRequest = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* All code below is taken from or based on Google's Protocol Buffers implementation: */
|
/* All code below is taken from or based on Google's Protocol Buffers implementation: */
|
||||||
|
|
||||||
// Protocol Buffers - Google's data interchange format
|
// Protocol Buffers - Google's data interchange format
|
||||||
@ -727,17 +782,4 @@ public class MapDatabase implements IMapDatabase {
|
|||||||
return (n >>> 1) ^ -(n & 1);
|
return (n >>> 1) ^ -(n & 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean mCanceled;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void cancel() {
|
|
||||||
mCanceled = true;
|
|
||||||
if (mRequest != null) {
|
|
||||||
mRequest.abort();
|
|
||||||
mRequest = null;
|
|
||||||
}
|
|
||||||
// mClient.getConnectionManager().shutdown();
|
|
||||||
// mClient = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -45,14 +45,14 @@ import android.util.Log;
|
|||||||
public class MapDatabase implements IMapDatabase {
|
public class MapDatabase implements IMapDatabase {
|
||||||
private final static String TAG = "MapDatabase";
|
private final static String TAG = "MapDatabase";
|
||||||
|
|
||||||
private static final String QUERY = "SELECT tags, geom FROM __get_tile(?,?,?)";
|
private static final String QUERY = "SELECT tags, geom FROM __get_tile(?,?,?,false)";
|
||||||
|
|
||||||
private final float mScale = 1; // 1000000.0f;
|
private final float mScale = 1;
|
||||||
|
|
||||||
private int mCoordPos = 0;
|
private int mCoordPos = 0;
|
||||||
private int mIndexPos = 0;
|
private int mIndexPos = 0;
|
||||||
private float[] mCoords = new float[100000];
|
private float[] mCoords;
|
||||||
private short[] mIndex = new short[10000];
|
private short[] mIndex;
|
||||||
|
|
||||||
private Tag[] mTags;
|
private Tag[] mTags;
|
||||||
|
|
||||||
@ -71,7 +71,7 @@ public class MapDatabase implements IMapDatabase {
|
|||||||
|
|
||||||
private boolean connect() {
|
private boolean connect() {
|
||||||
Connection conn = null;
|
Connection conn = null;
|
||||||
String dburl = "jdbc:postgresql://city.informatik.uni-bremen.de:5432/gis-2.0";
|
String dburl = "jdbc:postgresql://city.informatik.uni-bremen.de:5432/gis";
|
||||||
|
|
||||||
Properties dbOpts = new Properties();
|
Properties dbOpts = new Properties();
|
||||||
dbOpts.setProperty("user", "osm");
|
dbOpts.setProperty("user", "osm");
|
||||||
@ -212,6 +212,10 @@ public class MapDatabase implements IMapDatabase {
|
|||||||
@Override
|
@Override
|
||||||
public FileOpenResult openFile(File mapFile) {
|
public FileOpenResult openFile(File mapFile) {
|
||||||
mOpenFile = true;
|
mOpenFile = true;
|
||||||
|
if (mCoords == null) {
|
||||||
|
mCoords = new float[100000];
|
||||||
|
mIndex = new short[100000];
|
||||||
|
}
|
||||||
return new FileOpenResult();
|
return new FileOpenResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,6 +230,8 @@ public class MapDatabase implements IMapDatabase {
|
|||||||
connection = null;
|
connection = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mCoords = null;
|
||||||
|
mIndex = null;
|
||||||
mOpenFile = false;
|
mOpenFile = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user