From d74e5a7d00dc90c917b210c3540027598257dad2 Mon Sep 17 00:00:00 2001 From: Hannes Janetzek Date: Thu, 11 Apr 2013 23:06:17 +0200 Subject: [PATCH] - use clipping for PathOverlay, now Great Circle works properly --- src/org/oscim/overlay/PathOverlay.java | 106 +++++++++++++++----- src/org/oscim/renderer/layer/LineLayer.java | 20 +++- src/org/oscim/view/MapView.java | 7 ++ 3 files changed, 104 insertions(+), 29 deletions(-) diff --git a/src/org/oscim/overlay/PathOverlay.java b/src/org/oscim/overlay/PathOverlay.java index 3b8b870f..bf8a1be5 100644 --- a/src/org/oscim/overlay/PathOverlay.java +++ b/src/org/oscim/overlay/PathOverlay.java @@ -34,7 +34,6 @@ import org.oscim.utils.FastMath; import org.oscim.utils.LineClipper; import org.oscim.view.MapView; - /** This class draws a path line in given color. */ public class PathOverlay extends Overlay { @@ -43,13 +42,13 @@ public class PathOverlay extends Overlay { /* package */boolean mUpdatePoints; /** Line style */ - /* package */ Line mLineStyle; + /* package */Line mLineStyle; class RenderPath extends BasicOverlay { private static final byte MAX_ZOOM = 20; 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 private int[] mPreprojected; @@ -57,7 +56,6 @@ public class PathOverlay extends Overlay { // projected points private float[] mPPoints; - private final short[] mIndex; private int mSize; private final LineClipper mClipper; @@ -66,8 +64,7 @@ public class PathOverlay extends Overlay { public RenderPath(MapView mapView) { super(mapView); - mClipper = new LineClipper(-max, -max, max, max); - mIndex = new short[1]; + mClipper = new LineClipper(-max, -max, max, max, true); mPPoints = new float[1]; mMapPoint = new PointD(); MAX_SCALE = (1 << MAX_ZOOM) * Tile.SIZE; @@ -110,6 +107,13 @@ public class PathOverlay extends Overlay { } int size = mSize; + if (size == 0) { + if (layers.baseLayers != null) { + layers.clear(); + newData = true; + } + return; + } LineLayer ll = (LineLayer) layers.getLayer(1, Layer.LINE); ll.line = mLineStyle; @@ -118,42 +122,87 @@ public class PathOverlay extends Overlay { // Hack: reset verticesCnt to reuse layer ll.verticesCnt = 0; - int x, y, px = 0, py = 0; - int i = 0; + int x, y, prevX, prevY; int z = curPos.zoomLevel; int diff = MAX_ZOOM - z; int mx = (int) (curPos.x * (Tile.SIZE << z)); int my = (int) (curPos.y * (Tile.SIZE << z)); - for (int j = 0; j < size; j += 2) { - // TODO translate mapPosition and do this after clipping + int j = 0; + + // 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; y = (mPreprojected[j + 1] >> diff) - my; - // TODO use line clipping, this doesnt work with 'GreatCircle' - // TODO clip to view bounding box - if (x > max || x < -max || y > max || y < -max) { - if (i > 2) { - mIndex[0] = (short) i; - ll.addLine(projected, mIndex, false); + int curFlip = 0; + if (x > flipMax) { + x -= flipMax * 2; + curFlip = -1; + } else if (x < -flipMax) { + 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; continue; } - // skip too near points - int dx = x - px; - int dy = y - py; + int dx = x - prevX; + int dy = y - prevY; if ((i == 0) || FastMath.absMaxCmp(dx, dy, MIN_DIST)) { - projected[i + 0] = px = x; - projected[i + 1] = py = y; - i += 2; + projected[i++] = prevX = x; + projected[i++] = prevY = y; } } - - mIndex[0] = (short) i; - ll.addLine(projected, mIndex, false); + if (i > 2) + ll.addLine(projected, i, false); // keep position to render relative to current state mMapPosition.copy(curPos); @@ -163,6 +212,12 @@ public class PathOverlay extends Overlay { 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) { @@ -178,6 +233,7 @@ public class PathOverlay extends Overlay { public PathOverlay(MapView mapView, int lineColor) { this(mapView, lineColor, 2); } + /** * Draw a great circle. Calculate a point for every 100km along the path. * diff --git a/src/org/oscim/renderer/layer/LineLayer.java b/src/org/oscim/renderer/layer/LineLayer.java index a3645f4a..c9dcfb18 100644 --- a/src/org/oscim/renderer/layer/LineLayer.java +++ b/src/org/oscim/renderer/layer/LineLayer.java @@ -23,7 +23,6 @@ import org.oscim.theme.renderinstruction.Line; import org.oscim.utils.FastMath; import org.oscim.view.MapView; - /** */ public final class LineLayer extends Layer { @@ -70,6 +69,15 @@ public final class LineLayer extends Layer { * whether to connect start- and end-point. */ 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 a, ux, uy, vx, vy, wx, wy; @@ -113,10 +121,14 @@ public final class LineLayer extends Layer { int n; int length = 0; - if (index == null){ + if (index == null) { n = 1; - length = points.length; - } else{ + if (numPoints > 0) { + length = numPoints; + } else { + length = points.length; + } + } else { n = index.length; } diff --git a/src/org/oscim/view/MapView.java b/src/org/oscim/view/MapView.java index ddc47222..aea3a96b 100644 --- a/src/org/oscim/view/MapView.java +++ b/src/org/oscim/view/MapView.java @@ -193,6 +193,13 @@ public class MapView extends RelativeLayout { //mOverlayManager.add(new GenericOverlay(this, new CustomOverlay(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(); }