- improve way-labeling

- let nomination search places instead of tags
This commit is contained in:
Hannes Janetzek 2012-11-03 14:45:34 +01:00
parent 0eda94864f
commit b7aaaef485
14 changed files with 260 additions and 73 deletions

View File

@ -65,7 +65,7 @@ public class MapDatabase implements IMapDatabase {
private static final String CACHE_FILE = "%d-%d-%d.tile"; private static final String CACHE_FILE = "%d-%d-%d.tile";
private static final String SERVER_ADDR = "city.informatik.uni-bremen.de"; private static final String SERVER_ADDR = "city.informatik.uni-bremen.de";
// private static final String URL = "/osci/map-live/"; //private static final String URL = "/osci/map-live/";
private static final String URL = "/osci/oscim/"; private static final String URL = "/osci/oscim/";
private final static float REF_TILE_SIZE = 4096.0f; private final static float REF_TILE_SIZE = 4096.0f;

View File

@ -94,6 +94,8 @@ public class MapDatabase implements IMapDatabase {
// private static final String URL = // private static final String URL =
// "http://city.informatik.uni-bremen.de:8020/test/%d/%d/%d.osmtile"; // "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/gis-live/%d/%d/%d.osmtile";
// private static final String URL = // private static final String URL =
// "http://city.informatik.uni-bremen.de/tiles/tiles.py///test/%d/%d/%d.osmtile"; // "http://city.informatik.uni-bremen.de/tiles/tiles.py///test/%d/%d/%d.osmtile";
// private static final String URL = // private static final String URL =
@ -1217,10 +1219,8 @@ public class MapDatabase implements IMapDatabase {
mCacheFile = null; mCacheFile = null;
} }
/* /* All code below is taken from or based on Google's Protocol Buffers
* All code below is taken from or based on Google's Protocol Buffers * implementation: */
* implementation:
*/
// Protocol Buffers - Google's data interchange format // Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc. All rights reserved. // Copyright 2008 Google Inc. All rights reserved.

View File

@ -170,7 +170,7 @@ public final class LineRenderer {
blur = true; blur = true;
} }
if (line.cap == Cap.ROUND) { if (o.line.cap == Cap.ROUND) {
if (lineMode != 1) { if (lineMode != 1) {
lineMode = 1; lineMode = 1;
GLES20.glUniform1i(hLineMode[mode], lineMode); GLES20.glUniform1i(hLineMode[mode], lineMode);

View File

@ -160,10 +160,8 @@ public abstract class ScanBox {
} }
} }
/* /* ported from Polymaps: Layer.js Copyright (c) 2010, SimpleGeo and Stamen
* ported from Polymaps: Layer.js Copyright (c) 2010, SimpleGeo and Stamen * Design */
* Design
*/
// // scan-line conversion // // scan-line conversion
// function edge(a, b) { // function edge(a, b) {

View File

@ -24,6 +24,7 @@ import org.oscim.renderer.layer.TextureLayer;
import org.oscim.utils.GlUtils; import org.oscim.utils.GlUtils;
import android.opengl.GLES20; import android.opengl.GLES20;
import android.util.FloatMath;
import android.util.Log; import android.util.Log;
public final class TextureRenderer { public final class TextureRenderer {
@ -42,7 +43,7 @@ public final class TextureRenderer {
final static int VERTICES_PER_SPRITE = 4; final static int VERTICES_PER_SPRITE = 4;
final static int SHORTS_PER_VERTICE = 6; final static int SHORTS_PER_VERTICE = 6;
// per texture // per texture
public final static int MAX_ITEMS = 50; private final static int MAX_ITEMS = 50;
static void init() { static void init() {
mTextureProgram = GlUtils.createProgram(Shaders.textVertexShader, mTextureProgram = GlUtils.createProgram(Shaders.textVertexShader,
@ -111,7 +112,8 @@ public final class TextureRenderer {
TextureLayer tl = (TextureLayer) layer; TextureLayer tl = (TextureLayer) layer;
if (tl.fixed) if (tl.fixed)
GLES20.glUniform1f(hTextureScale, scale);
GLES20.glUniform1f(hTextureScale, FloatMath.sqrt(scale));
else else
GLES20.glUniform1f(hTextureScale, 1); GLES20.glUniform1f(hTextureScale, 1);
@ -129,6 +131,7 @@ public final class TextureRenderer {
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, to.id); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, to.id);
int maxVertices = MAX_ITEMS * INDICES_PER_SPRITE; int maxVertices = MAX_ITEMS * INDICES_PER_SPRITE;
// can only draw MAX_ITEMS in each iteration
for (int i = 0; i < to.vertices; i += maxVertices) { for (int i = 0; i < to.vertices; i += maxVertices) {
// to.offset * (24(shorts) * 2(short-bytes) / 6(indices) == 8) // to.offset * (24(shorts) * 2(short-bytes) / 6(indices) == 8)
int off = (to.offset + i) * 8 + offset; int off = (to.offset + i) * 8 + offset;

View File

@ -179,7 +179,7 @@ public final class WayDecorator {
wayNameWidth = text.paint.measureText(string); wayNameWidth = text.paint.measureText(string);
} }
if (segmentLengthInPixel > wayNameWidth + 25) { if (segmentLengthInPixel > wayNameWidth * 0.80) {
float s = (wayNameWidth + 25) / segmentLengthInPixel; float s = (wayNameWidth + 25) / segmentLengthInPixel;
int width, height; int width, height;
@ -244,17 +244,17 @@ public final class WayDecorator {
// Log.d("mapsforge", "add " + text + " " + first + " " + // Log.d("mapsforge", "add " + text + " " + first + " " +
// last); // last);
if (previousX < currentX) { // if (previousX < currentX) {
x1 = previousX; // x1 = previousX;
y1 = previousY; // y1 = previousY;
x2 = currentX; // x2 = currentX;
y2 = currentY; // y2 = currentY;
} else { // } else {
x1 = currentX; // x1 = currentX;
y1 = currentY; // y1 = currentY;
x2 = previousX; // x2 = previousX;
y2 = previousY; // y2 = previousY;
} // }
// if (t == null) // if (t == null)
t = TextItem.get(); t = TextItem.get();

View File

@ -119,7 +119,7 @@ public final class SymbolLayer extends TextureLayer {
textures = to; textures = to;
mCanvas.setBitmap(to.bitmap); mCanvas.setBitmap(to.bitmap);
int maxIndices = TextureRenderer.MAX_ITEMS * TextureRenderer.INDICES_PER_SPRITE; // int maxIndices = TextureRenderer.MAX_ITEMS * TextureRenderer.INDICES_PER_SPRITE;
for (SymbolItem it = symbols; it != null;) { for (SymbolItem it = symbols; it != null;) {
float width, height; float width, height;
@ -143,7 +143,7 @@ public final class SymbolLayer extends TextureLayer {
} }
if (y + height > TEXTURE_HEIGHT || curIndices == maxIndices) { if (y + height > TEXTURE_HEIGHT) { // || curIndices == maxIndices) {
Log.d(TAG, "reached max symbols: " + numIndices); Log.d(TAG, "reached max symbols: " + numIndices);
to.offset = offsetIndices; to.offset = offsetIndices;
@ -249,13 +249,6 @@ public final class SymbolLayer extends TextureLayer {
pos = 0; pos = 0;
} }
// FIXME this does not work, need to draw bitmap on next
// texture...
// if (pos == bufLen) {
// sbuf.put(buf, 0, pos);
// pos = 0;
// }
x += width; x += width;
} }
} }

View File

@ -68,6 +68,15 @@ public class TextItem {
return this; return this;
} }
public TextItem move(TextItem ti, float dx, float dy, float scale) {
this.x = dx + (ti.x * scale);
this.y = dy + (ti.y * scale);
this.string = ti.string;
this.text = ti.text;
this.width = ti.width;
return this;
}
public TextItem next; public TextItem next;
public float x, y; public float x, y;

View File

@ -35,9 +35,9 @@ public final class TextLayer extends TextureLayer {
private static int mFontPadX = 1; private static int mFontPadX = 1;
private static int mFontPadY = 1; private static int mFontPadY = 1;
TextItem labels; public TextItem labels;
private Canvas mCanvas; private Canvas mCanvas;
private float mScale;
public TextItem getLabels() { public TextItem getLabels() {
return labels; return labels;
@ -47,6 +47,31 @@ public final class TextLayer extends TextureLayer {
type = Layer.SYMBOL; type = Layer.SYMBOL;
mCanvas = new Canvas(); mCanvas = new Canvas();
fixed = true; fixed = true;
mScale = 1;
}
public void setScale(float scale) {
mScale = scale;
}
public boolean removeText(TextItem item) {
TextItem prev = null;
for (TextItem it = labels; it != null; it = it.next) {
if (it == item) {
if (prev == null)
labels = it.next;
else
prev.next = it.next;
verticesCnt -= 4;
return true;
}
prev = it;
}
return false;
} }
public void addText(TextItem item) { public void addText(TextItem item) {
@ -170,8 +195,14 @@ public final class TextLayer extends TextureLayer {
float ux = -vy; float ux = -vy;
float uy = vx; float uy = vx;
hw /= mScale;
float hh2 = hh + it.text.fontDescent / 2; float hh2 = hh + it.text.fontDescent / 2;
hh -= it.text.fontDescent / 2; hh -= it.text.fontDescent / 2;
hh /= mScale;
hh2 /= mScale;
x1 = (short) (SCALE * (vx * hw - ux * hh)); x1 = (short) (SCALE * (vx * hw - ux * hh));
y1 = (short) (SCALE * (vy * hw - uy * hh)); y1 = (short) (SCALE * (vy * hw - uy * hh));
x2 = (short) (SCALE * (-vx * hw - ux * hh)); x2 = (short) (SCALE * (-vx * hw - ux * hh));

View File

@ -17,15 +17,18 @@ package org.oscim.renderer.overlays;
import org.oscim.core.MapPosition; import org.oscim.core.MapPosition;
import org.oscim.core.Tile; import org.oscim.core.Tile;
import org.oscim.renderer.GLRenderer;
import org.oscim.renderer.MapTile; import org.oscim.renderer.MapTile;
import org.oscim.renderer.TileManager; import org.oscim.renderer.TileManager;
import org.oscim.renderer.Tiles; import org.oscim.renderer.Tiles;
import org.oscim.renderer.layer.TextItem; import org.oscim.renderer.layer.TextItem;
import org.oscim.renderer.layer.TextLayer; import org.oscim.renderer.layer.TextLayer;
import org.oscim.utils.FastMath; import org.oscim.utils.FastMath;
import org.oscim.utils.GeometryUtils;
import org.oscim.utils.PausableThread; import org.oscim.utils.PausableThread;
import org.oscim.view.MapView; import org.oscim.view.MapView;
import android.opengl.Matrix;
import android.os.SystemClock; import android.os.SystemClock;
import android.util.FloatMath; import android.util.FloatMath;
@ -45,7 +48,7 @@ public class OverlayText extends RenderOverlay {
@Override @Override
protected void doWork() { protected void doWork() {
SystemClock.sleep(300); SystemClock.sleep(500);
mRun = false; mRun = false;
updateLabels(); updateLabels();
mMapView.redrawMap(); mMapView.redrawMap();
@ -96,54 +99,131 @@ public class OverlayText extends RenderOverlay {
return; return;
} }
float div = FastMath.pow(diff); float scale = mWorkPos.scale;
// fix map position to tile coordinates
float size = Tile.TILE_SIZE;
int x = (int) (mWorkPos.x / div / size);
int y = (int) (mWorkPos.y / div / size);
mWorkPos.x = x * size;
mWorkPos.y = y * size;
mWorkPos.zoomLevel += diff;
mWorkPos.scale = div;
float angle = (float) Math.toRadians(mWorkPos.angle); float angle = (float) Math.toRadians(mWorkPos.angle);
float cos = FloatMath.cos(angle); float cos = FloatMath.cos(angle);
float sin = FloatMath.sin(angle); float sin = FloatMath.sin(angle);
TextItem ti2 = null;
// TODO more sophisticated placement :) // TODO more sophisticated placement :)
for (int i = 0, n = tiles.cnt; i < n; i++) { for (int i = 0, n = tiles.cnt; i < n; i++) {
MapTile t = tiles.tiles[i]; MapTile t = tiles.tiles[i];
if (!t.isVisible) if (!t.isVisible)
continue; continue;
int dx = (t.tileX - x) * Tile.TILE_SIZE; float dx = (float) ((t.pixelX - mWorkPos.x) * scale);
int dy = (t.tileY - y) * Tile.TILE_SIZE; float dy = (float) ((t.pixelY - mWorkPos.y) * scale);
for (TextItem ti = t.labels; ti != null; ti = ti.next) { for (TextItem ti = t.labels; ti != null; ti = ti.next) {
TextItem ti2 = TextItem.get().move(ti, dx, dy); if (ti2 == null)
ti2 = TextItem.get();
ti2.move(ti, dx, dy, scale);
boolean overlaps = false;
if (ti.text.caption) {
int tx = (int) (ti2.x);
int ty = (int) (ti2.y);
int tw = (int) (ti2.width / 2);
int th = (int) (ti2.text.fontHeight / 2);
for (TextItem lp = tl.labels; lp != null; lp = lp.next) {
int px = (int) (lp.x);
int py = (int) (lp.y);
int ph = (int) (lp.text.fontHeight / 2);
int pw = (int) (lp.width / 2);
if ((tx - tw) < (px + pw)
&& (px - pw) < (tx + tw)
&& (ty - th) < (py + ph)
&& (py - ph) < (ty + th)) {
overlaps = true;
break;
}
}
} else {
if (!ti.text.caption) {
if (cos * (ti.x2 - ti.x1) - sin * (ti.y2 - ti.y1) < 0) { if (cos * (ti.x2 - ti.x1) - sin * (ti.y2 - ti.y1) < 0) {
// flip label upside-down // flip label upside-down
ti2.x1 = ti.x2; ti2.x1 = (short) ((ti.x2 * scale + dx));
ti2.y1 = ti.y2; ti2.y1 = (short) ((ti.y2 * scale + dy));
ti2.x2 = ti.x1; ti2.x2 = (short) ((ti.x1 * scale + dx));
ti2.y2 = ti.y1; ti2.y2 = (short) ((ti.y1 * scale + dy));
} else { } else {
ti2.x1 = ti.x1; ti2.x1 = (short) ((ti.x1 * scale + dx));
ti2.y1 = ti.y1; ti2.y1 = (short) ((ti.y1 * scale + dy));
ti2.x2 = ti.x2; ti2.x2 = (short) ((ti.x2 * scale + dx));
ti2.y2 = ti.y2; ti2.y2 = (short) ((ti.y2 * scale + dy));
}
//float normalLength = (float) Math.hypot(ti2.x2 - ti2.x1, ti2.y2 - ti2.y1);
for (TextItem lp = tl.labels; lp != null;) {
if (lp.text.caption) {
lp = lp.next;
continue;
}
if (GeometryUtils.lineIntersect(ti2.x1, ti2.y1, ti2.x2, ti2.y2,
lp.x1, lp.y1, lp.x2, lp.y2)) {
// just to make it more deterministic
if (lp.width < ti2.width) {
TextItem tmp = lp;
lp = lp.next;
tl.removeText(tmp);
tmp.next = null;
TextItem.release(tmp);
continue;
}
overlaps = true;
break;
}
if ((ti2.x1) < (lp.x2)
&& (lp.x1) < (ti2.x2)
&& (ti2.y1) < (lp.y2)
&& (lp.y1) < (ti2.y2)) {
// just to make it more deterministic
if (lp.width < ti2.width) {
TextItem tmp = lp;
lp = lp.next;
tl.removeText(tmp);
tmp.next = null;
TextItem.release(tmp);
continue;
}
overlaps = true;
break;
}
lp = lp.next;
} }
} }
if (!overlaps) {
tl.addText(ti2); tl.addText(ti2);
ti2 = null;
} }
} }
}
if (ti2 != null)
TextItem.release(ti2);
// scale back to fixed zoom-level. could be done in setMatrix..
for (TextItem lp = tl.labels; lp != null; lp = lp.next) {
lp.x /= scale;
lp.y /= scale;
}
// draw text to bitmaps and create vertices // draw text to bitmaps and create vertices
tl.setScale(scale);
tl.prepare(); tl.prepare();
// everything synchronized? // everything synchronized?
@ -153,7 +233,8 @@ public class OverlayText extends RenderOverlay {
} }
@Override @Override
public synchronized void update(MapPosition curPos, boolean positionChanged, boolean tilesChanged) { public synchronized void update(MapPosition curPos, boolean positionChanged,
boolean tilesChanged) {
// Log.d("...", "update " + tilesChanged + " " + positionChanged); // Log.d("...", "update " + tilesChanged + " " + positionChanged);
if (mNewLayer != null) { if (mNewLayer != null) {
@ -183,4 +264,43 @@ public class OverlayText extends RenderOverlay {
} }
} }
} }
@Override
protected float setMatrix(MapPosition curPos, float[] matrix) {
// TODO if oPos == curPos this could be simplified
MapPosition oPos = mMapPosition;
byte z = oPos.zoomLevel;
float div = FastMath.pow(z - curPos.zoomLevel);
float x = (float) (oPos.x - curPos.x * div);
float y = (float) (oPos.y - curPos.y * div);
// flip around date-line
float max = (Tile.TILE_SIZE << z);
if (x < -max / 2)
x = max + x;
else if (x > max / 2)
x = x - max;
float scale = curPos.scale / div;
Matrix.setIdentityM(matrix, 0);
// translate relative to map center
matrix[12] = x * scale;
matrix[13] = y * scale;
// scale to current tile world coordinates
scale = curPos.scale / div; // oPos.scale / div;
scale /= GLRenderer.COORD_MULTIPLIER;
matrix[0] = scale;
matrix[5] = scale;
Matrix.multiplyMM(matrix, 0, curPos.viewMatrix, 0, matrix, 0);
return div;
}
} }

View File

@ -54,7 +54,6 @@ public abstract class RenderOverlay {
/** /**
* Utility: update mMapPosition * Utility: update mMapPosition
*
* @return true if position has changed * @return true if position has changed
*/ */
protected boolean updateMapPosition() { protected boolean updateMapPosition() {
@ -71,7 +70,8 @@ public abstract class RenderOverlay {
* @param tilesChanged * @param tilesChanged
* true when loaded tiles changed * true when loaded tiles changed
*/ */
public synchronized void update(MapPosition curPos, boolean positionChanged, boolean tilesChanged) { public synchronized void update(MapPosition curPos, boolean positionChanged,
boolean tilesChanged) {
// // keep position constant (or update layer relative to new position) // // keep position constant (or update layer relative to new position)
// mMapView.getMapViewPosition().getMapPosition(mMapPosition, null); // mMapView.getMapViewPosition().getMapPosition(mMapPosition, null);
// //
@ -114,7 +114,8 @@ public abstract class RenderOverlay {
} }
} }
private float setMatrix(MapPosition curPos, float[] matrix) { // set matrix to scale relative to zoomlevel
protected float setMatrix(MapPosition curPos, float[] matrix) {
// TODO if oPos == curPos this could be simplified // TODO if oPos == curPos this could be simplified
MapPosition oPos = mMapPosition; MapPosition oPos = mMapPosition;

View File

@ -497,7 +497,26 @@
<!-- highway --> <!-- highway -->
<rule e="way" k="highway" v="*"> <rule e="way" k="highway" v="*">
<rule e="way" k="*" v="*" zoom-min="3" zoom-max="10"> <rule e="way" k="*" v="*" zoom-min="3" zoom-max="5">
<rule e="way" k="area" v="~|no|false">
<!-- <rule e="way" k="*" v="secondary|primary_link" zoom-min="9">
<line stroke="#f2df6d" width="1.3" cap="butt" fixed="true" fade="9"/>
</rule> -->
<rule e="way" k="*" v="route_primary" zoom-min="3">
<line stroke="#f2df6d" width="1.4" cap="butt" fixed="true" fade="3"/>
</rule>
<rule e="way" k="*" v="route_trunk" zoom-min="3">
<line stroke="#fed6a3" width="1.4" cap="butt" fixed="true" fade="3"/>
</rule>
<rule e="way" k="*" v="route_motorway">
<line stroke="#eec693" width="1.5" cap="butt" fixed="true" fade="3"/>
</rule>
</rule>
</rule>
<rule e="way" k="*" v="*" zoom-min="5" zoom-max="10">
<rule e="way" k="area" v="~|no|false"> <rule e="way" k="area" v="~|no|false">
<rule e="way" k="*" v="secondary|primary_link" zoom-min="9"> <rule e="way" k="*" v="secondary|primary_link" zoom-min="9">
<line stroke="#f2df6d" width="1.3" cap="butt" fixed="true" fade="9"/> <line stroke="#f2df6d" width="1.3" cap="butt" fixed="true" fade="9"/>
@ -916,7 +935,7 @@
</rule> </rule>
<rule e="node" k="debug" v="*" > <rule e="node" k="debug" v="*" >
<caption k="name" font-size="12" fill="#0000ff" /> <caption k="name" font-size="16" fill="#0000ff" />
</rule> </rule>
@ -941,7 +960,7 @@
<!-- place --> <!-- place -->
<rule e="node" k="place" v="*"> <rule e="node" k="place" v="*">
<rule e="node" k="*" v="suburb|town|village"> <rule e="node" k="*" v="suburb|town|village">
<caption k="name" font-size="18" fill="#000000" <caption k="name" font-size="17" fill="#000000"
stroke="#ffffff" stroke-width="2.0" /> stroke="#ffffff" stroke-width="2.0" />
</rule> </rule>
<rule e="node" k="*" v="island" zoom-min="10"> <rule e="node" k="*" v="island" zoom-min="10">
@ -949,7 +968,7 @@
stroke="#ffffff" stroke-width="2.0" /> stroke="#ffffff" stroke-width="2.0" />
</rule> </rule>
<rule e="node" k="*" v="city"> <rule e="node" k="*" v="city">
<caption k="name" font-size="19" fill="#000000" <caption k="name" font-size="20" fill="#000000"
stroke="#ffffff" stroke-width="2.0" /> stroke="#ffffff" stroke-width="2.0" />
</rule> </rule>
<rule e="node" k="*" v="country"> <rule e="node" k="*" v="country">

View File

@ -14,6 +14,8 @@
*/ */
package org.oscim.utils; package org.oscim.utils;
import android.graphics.Point;
/** /**
* *
* *
@ -22,7 +24,6 @@ public final class GeometryUtils {
/** /**
* Calculates the center of the minimum bounding rectangle for the given * Calculates the center of the minimum bounding rectangle for the given
* coordinates. * coordinates.
*
* @param coordinates * @param coordinates
* the coordinates for which calculation should be done. * the coordinates for which calculation should be done.
* @return the center coordinates of the minimum bounding rectangle. * @return the center coordinates of the minimum bounding rectangle.
@ -165,12 +166,12 @@ public final class GeometryUtils {
*/ */
public static boolean lineIntersect(int x1, int y1, int x2, int y2, int x3, int y3, int x4, public static boolean lineIntersect(int x1, int y1, int x2, int y2, int x3, int y3, int x4,
int y4) { int y4) {
double denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1); float denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
if (denom == 0.0) { // Lines are parallel. if (denom == 0.0) { // Lines are parallel.
return false; return false;
} }
double ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denom; float ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denom;
double ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denom; float ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denom;
if (ua >= 0.0f && ua <= 1.0f && ub >= 0.0f && ub <= 1.0f) { if (ua >= 0.0f && ua <= 1.0f && ub >= 0.0f && ub <= 1.0f) {
// Get the intersection point. // Get the intersection point.
return true; return true;
@ -178,4 +179,11 @@ public final class GeometryUtils {
return false; return false;
} }
// http://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line
public static double pointToLineDistance(Point A, Point B, Point P) {
double normalLength = Math.hypot(B.x - A.x, B.y - A.y);
return Math.abs((P.x - A.x) * (B.y - A.y) - (P.y - A.y) * (B.x - A.x)) / normalLength;
}
} }

View File

@ -215,7 +215,8 @@ public class MapView extends RelativeLayout {
worker.start(); worker.start();
mOverlayManager.add(new LabelingOverlay(this)); mOverlayManager.add(new LabelingOverlay(this));
// mOverlayManager.add(new GenericOverlay(this, new OverlayGrid(this))); //mOverlayManager.add(new GenericOverlay(this, new OverlayGrid(this)));
// mOverlayManager.add(new GenericOverlay(this, new OverlayTest(this))); // mOverlayManager.add(new GenericOverlay(this, new OverlayTest(this)));
// ArrayList<OverlayItem> pList = new ArrayList<OverlayItem>(); // ArrayList<OverlayItem> pList = new ArrayList<OverlayItem>();
@ -710,6 +711,10 @@ public class MapView extends RelativeLayout {
return mMapViewPosition.getViewBox(); return mMapViewPosition.getViewBox();
} }
public GeoPoint getCenter() {
return new GeoPoint(mMapPosition.lat, mMapPosition.lon);
}
// @Override // @Override
// protected void onLayout(boolean changed, int l, int t, int r, int b) { // protected void onLayout(boolean changed, int l, int t, int r, int b) {
// // TODO Auto-generated method stub // // TODO Auto-generated method stub