- use clipping for PathOverlay, now Great Circle works properly

This commit is contained in:
Hannes Janetzek
2013-04-11 23:06:17 +02:00
parent 55a83aaf6f
commit d74e5a7d00
3 changed files with 104 additions and 29 deletions

View File

@@ -34,7 +34,6 @@ import org.oscim.utils.FastMath;
import org.oscim.utils.LineClipper; import org.oscim.utils.LineClipper;
import org.oscim.view.MapView; import org.oscim.view.MapView;
/** This class draws a path line in given color. */ /** This class draws a path line in given color. */
public class PathOverlay extends Overlay { public class PathOverlay extends Overlay {
@@ -43,13 +42,13 @@ public class PathOverlay extends Overlay {
/* package */boolean mUpdatePoints; /* package */boolean mUpdatePoints;
/** Line style */ /** Line style */
/* package */ Line mLineStyle; /* package */Line mLineStyle;
class RenderPath extends BasicOverlay { class RenderPath extends BasicOverlay {
private static final byte MAX_ZOOM = 20; private static final byte MAX_ZOOM = 20;
private final double MAX_SCALE; private final double MAX_SCALE;
private static final int MIN_DIST = 4; private static final int MIN_DIST = 2;
// pre-projected points to zoomlovel 20 // pre-projected points to zoomlovel 20
private int[] mPreprojected; private int[] mPreprojected;
@@ -57,7 +56,6 @@ public class PathOverlay extends Overlay {
// projected points // projected points
private float[] mPPoints; private float[] mPPoints;
private final short[] mIndex;
private int mSize; private int mSize;
private final LineClipper mClipper; private final LineClipper mClipper;
@@ -66,8 +64,7 @@ public class PathOverlay extends Overlay {
public RenderPath(MapView mapView) { public RenderPath(MapView mapView) {
super(mapView); super(mapView);
mClipper = new LineClipper(-max, -max, max, max); mClipper = new LineClipper(-max, -max, max, max, true);
mIndex = new short[1];
mPPoints = new float[1]; mPPoints = new float[1];
mMapPoint = new PointD(); mMapPoint = new PointD();
MAX_SCALE = (1 << MAX_ZOOM) * Tile.SIZE; MAX_SCALE = (1 << MAX_ZOOM) * Tile.SIZE;
@@ -110,6 +107,13 @@ public class PathOverlay extends Overlay {
} }
int size = mSize; int size = mSize;
if (size == 0) {
if (layers.baseLayers != null) {
layers.clear();
newData = true;
}
return;
}
LineLayer ll = (LineLayer) layers.getLayer(1, Layer.LINE); LineLayer ll = (LineLayer) layers.getLayer(1, Layer.LINE);
ll.line = mLineStyle; ll.line = mLineStyle;
@@ -118,42 +122,87 @@ public class PathOverlay extends Overlay {
// Hack: reset verticesCnt to reuse layer // Hack: reset verticesCnt to reuse layer
ll.verticesCnt = 0; ll.verticesCnt = 0;
int x, y, px = 0, py = 0; int x, y, prevX, prevY;
int i = 0;
int z = curPos.zoomLevel; int z = curPos.zoomLevel;
int diff = MAX_ZOOM - z; int diff = MAX_ZOOM - z;
int mx = (int) (curPos.x * (Tile.SIZE << z)); int mx = (int) (curPos.x * (Tile.SIZE << z));
int my = (int) (curPos.y * (Tile.SIZE << z)); int my = (int) (curPos.y * (Tile.SIZE << z));
for (int j = 0; j < size; j += 2) { int j = 0;
// TODO translate mapPosition and do this after clipping
// flip around dateline. complicated stuff..
int flip = 0;
int flipMax = Tile.SIZE << (z - 1);
x = (mPreprojected[j++] >> diff) - mx;
y = (mPreprojected[j++] >> diff) - my;
if (x > flipMax) {
x -= (flipMax * 2);
flip = -1;
} else if (x < -flipMax) {
x += (flipMax * 2);
flip = 1;
}
mClipper.clipStart(x, y);
int i = addPoint(projected, 0, x, y);
prevX = x;
prevY = y;
for (; j < size; j += 2) {
x = (mPreprojected[j + 0] >> diff) - mx; x = (mPreprojected[j + 0] >> diff) - mx;
y = (mPreprojected[j + 1] >> diff) - my; y = (mPreprojected[j + 1] >> diff) - my;
// TODO use line clipping, this doesnt work with 'GreatCircle' int curFlip = 0;
// TODO clip to view bounding box if (x > flipMax) {
if (x > max || x < -max || y > max || y < -max) { x -= flipMax * 2;
if (i > 2) { curFlip = -1;
mIndex[0] = (short) i; } else if (x < -flipMax) {
ll.addLine(projected, mIndex, false); x += flipMax * 2;
curFlip = 1;
}
if (flip != curFlip) {
flip = curFlip;
if (i > 2)
ll.addLine(projected, i, false);
mClipper.clipStart(x, y);
i = addPoint(projected, 0, x, y);
continue;
}
int clip = mClipper.clipNext(x, y);
if (clip < 1) {
if (i > 2)
ll.addLine(projected, i, false);
if (clip < 0) {
// add line segment
projected[0] = mClipper.out[0];
projected[1] = mClipper.out[1];
projected[2] = prevX = mClipper.out[2];
projected[3] = prevY = mClipper.out[3];
ll.addLine(projected, 4, false);
} }
i = 0; i = 0;
continue; continue;
} }
// skip too near points int dx = x - prevX;
int dx = x - px; int dy = y - prevY;
int dy = y - py;
if ((i == 0) || FastMath.absMaxCmp(dx, dy, MIN_DIST)) { if ((i == 0) || FastMath.absMaxCmp(dx, dy, MIN_DIST)) {
projected[i + 0] = px = x; projected[i++] = prevX = x;
projected[i + 1] = py = y; projected[i++] = prevY = y;
i += 2;
} }
} }
if (i > 2)
mIndex[0] = (short) i; ll.addLine(projected, i, false);
ll.addLine(projected, mIndex, false);
// keep position to render relative to current state // keep position to render relative to current state
mMapPosition.copy(curPos); mMapPosition.copy(curPos);
@@ -163,6 +212,12 @@ public class PathOverlay extends Overlay {
newData = true; newData = true;
} }
private int addPoint(float[] points, int i, int x, int y) {
points[i++] = x;
points[i++] = y;
return i;
}
} }
public PathOverlay(MapView mapView, int lineColor, float lineWidth) { public PathOverlay(MapView mapView, int lineColor, float lineWidth) {
@@ -178,6 +233,7 @@ public class PathOverlay extends Overlay {
public PathOverlay(MapView mapView, int lineColor) { public PathOverlay(MapView mapView, int lineColor) {
this(mapView, lineColor, 2); this(mapView, lineColor, 2);
} }
/** /**
* Draw a great circle. Calculate a point for every 100km along the path. * Draw a great circle. Calculate a point for every 100km along the path.
* *

View File

@@ -23,7 +23,6 @@ import org.oscim.theme.renderinstruction.Line;
import org.oscim.utils.FastMath; import org.oscim.utils.FastMath;
import org.oscim.view.MapView; import org.oscim.view.MapView;
/** /**
*/ */
public final class LineLayer extends Layer { public final class LineLayer extends Layer {
@@ -70,6 +69,15 @@ public final class LineLayer extends Layer {
* whether to connect start- and end-point. * whether to connect start- and end-point.
*/ */
public void addLine(float[] points, short[] index, boolean closed) { public void addLine(float[] points, short[] index, boolean closed) {
addLine(points, index, -1, closed);
}
public void addLine(float[] points, int numPoints, boolean closed) {
if (numPoints >= 4)
addLine(points, null, numPoints, closed);
}
private void addLine(float[] points, short[] index, int numPoints, boolean closed) {
float x, y, nextX, nextY; float x, y, nextX, nextY;
float a, ux, uy, vx, vy, wx, wy; float a, ux, uy, vx, vy, wx, wy;
@@ -113,10 +121,14 @@ public final class LineLayer extends Layer {
int n; int n;
int length = 0; int length = 0;
if (index == null){ if (index == null) {
n = 1; n = 1;
length = points.length; if (numPoints > 0) {
} else{ length = numPoints;
} else {
length = points.length;
}
} else {
n = index.length; n = index.length;
} }

View File

@@ -193,6 +193,13 @@ public class MapView extends RelativeLayout {
//mOverlayManager.add(new GenericOverlay(this, new CustomOverlay(this))); //mOverlayManager.add(new GenericOverlay(this, new CustomOverlay(this)));
//mOverlayManager.add(new MapLensOverlay(this)); //mOverlayManager.add(new MapLensOverlay(this));
//PathOverlay path = new PathOverlay(this, Color.RED);
//path.addGreatCircle(new GeoPoint(53.1, 8.8), new GeoPoint(53.1, -110.0));
//mOverlayManager.add(path);
//path = new PathOverlay(this, Color.GREEN);
//path.addGreatCircle(new GeoPoint(53.1, 140), new GeoPoint(53.1, -110.0));
//mOverlayManager.add(path);
clearMap(); clearMap();
} }