diff --git a/vtm/src/org/oscim/map/ViewController.java b/vtm/src/org/oscim/map/ViewController.java index e3eacda7..8237142b 100644 --- a/vtm/src/org/oscim/map/ViewController.java +++ b/vtm/src/org/oscim/map/ViewController.java @@ -11,6 +11,10 @@ import org.oscim.utils.ThreadUtils; public class ViewController extends Viewport { + protected float mPivotY = 0.0f; + + private final float[] mat = new float[16]; + public void setScreenSize(int width, int height) { ThreadUtils.assertMainThread(); @@ -26,19 +30,19 @@ public class ViewController extends Viewport { * 1. invert translate to VIEW_DISTANCE */ float ratio = (mHeight / mWidth) * VIEW_SCALE; - float[] tmp = new float[16]; - GLMatrix.frustumM(tmp, 0, -VIEW_SCALE, VIEW_SCALE, + GLMatrix.frustumM(mat, 0, -VIEW_SCALE, VIEW_SCALE, ratio, -ratio, VIEW_NEAR, VIEW_FAR); - mProjMatrix.set(tmp); + mProjMatrix.set(mat); + mTmpMatrix.setTranslation(0, 0, -VIEW_DISTANCE); mProjMatrix.multiplyRhs(mTmpMatrix); /* set inverse projection matrix (without scaling) */ - mProjMatrix.get(tmp); - GLMatrix.invertM(tmp, 0, tmp, 0); - mProjMatrixInverse.set(tmp); + mProjMatrix.get(mat); + GLMatrix.invertM(mat, 0, mat, 0); + mProjMatrixInverse.set(mat); mProjMatrixUnscaled.copy(mProjMatrix); @@ -49,6 +53,15 @@ public class ViewController extends Viewport { updateMatrices(); } + /** + * Set pivot height relative to screen center. E.g. 0.5 is usually preferred + * for navigation, moving the center to 25% of the screen height. + * Range is [-1, 1]. + */ + public void setMapScreenCenter(float pivotY) { + mPivotY = FastMath.clamp(pivotY, -1, 1) * 0.5f; + } + /** * Moves this Viewport by the given amount of pixels. * @@ -120,10 +133,12 @@ public class ViewController extends Viewport { mPos.scale = newScale; - if (pivotX != 0 || pivotY != 0) + if (pivotX != 0 || pivotY != 0) { + pivotY -= mHeight * mPivotY; + moveMap(pivotX * (1.0f - scale), pivotY * (1.0f - scale)); - + } return true; } @@ -141,6 +156,8 @@ public class ViewController extends Viewport { double rsin = Math.sin(radians); double rcos = Math.cos(radians); + pivotY -= mHeight * mPivotY; + float x = (float) (pivotX - pivotX * rcos + pivotY * rsin); float y = (float) (pivotY - pivotX * rsin - pivotY * rcos); @@ -202,20 +219,14 @@ public class ViewController extends Viewport { mViewMatrix.copy(mRotationMatrix); + mTmpMatrix.setTranslation(0, mPivotY * mHeight, 0); + mViewMatrix.multiplyLhs(mTmpMatrix); + mViewProjMatrix.multiplyMM(mProjMatrix, mViewMatrix); - /* inverse projection matrix: */ - /* invert scale */ - mUnprojMatrix.setScale(mWidth, mWidth, 1); - - /* invert rotation and tilt */ - mTmpMatrix.transposeM(mRotationMatrix); - - /* (AB)^-1 = B^-1*A^-1, invert scale, tilt and rotation */ - mTmpMatrix.multiplyLhs(mUnprojMatrix); - - /* (AB)^-1 = B^-1*A^-1, invert projection */ - mUnprojMatrix.multiplyMM(mTmpMatrix, mProjMatrixInverse); + mViewProjMatrix.get(mat); + GLMatrix.invertM(mat, 0, mat, 0); + mUnprojMatrix.set(mat); } public final Viewport mNextFrame = new Viewport(); diff --git a/vtm/src/org/oscim/map/Viewport.java b/vtm/src/org/oscim/map/Viewport.java index ac7b2cec..21bcad86 100644 --- a/vtm/src/org/oscim/map/Viewport.java +++ b/vtm/src/org/oscim/map/Viewport.java @@ -71,7 +71,7 @@ public class Viewport { /** scale map plane at VIEW_DISTANCE to near plane */ public final static float VIEW_SCALE = (VIEW_NEAR / VIEW_DISTANCE) * 0.5f; - protected Viewport() { + public Viewport() { mPos.scale = MIN_SCALE; mPos.x = 0.5; mPos.y = 0.5; @@ -115,17 +115,14 @@ public class Viewport { * @param add increase extents of box */ public void getMapExtents(float[] box, float add) { - float t = getDepth(1); - float t2 = getDepth(-1); - - // top-right - unproject(1, -1, t, box, 0); - // top-left - unproject(-1, -1, t, box, 2); - // bottom-left - unproject(-1, 1, t2, box, 4); - // bottom-right - unproject(1, 1, t2, box, 6); + /* top-right */ + unproject(1, -1, box, 0); + /* top-left */ + unproject(-1, -1, box, 2); + /* bottom-left */ + unproject(-1, 1, box, 4); + /* bottom-right */ + unproject(1, 1, box, 6); if (add == 0) return; @@ -139,49 +136,31 @@ public class Viewport { } } - /** - * Get Z-value of the map-plane for a point on screen - - * calculate the intersection of a ray from camera origin - * and the map plane - * TODO use - * www.comp.nus.edu.sg/~lowkl/publications/lowk_persp_interp_techrep.pdf - */ - protected float getDepth(float y) { - // origin is moved by VIEW_DISTANCE - double cx = VIEW_DISTANCE; - // 'height' of the ray - double ry = y * (mHeight / mWidth) * 0.5f; - - double ua; - - if (y == 0) - ua = 1; - else { - // tilt of the plane (center is kept on x = 0) - double t = Math.toRadians(mPos.tilt); - double px = y * Math.sin(t); - double py = y * Math.cos(t); - ua = 1 + (px * ry) / (py * cx); - } - - mv[0] = 0; - mv[1] = (float) (ry / ua); - mv[2] = (float) (cx - cx / ua); - - mProjMatrixUnscaled.prj(mv); - - return mv[2]; - } - - protected void unproject(float x, float y, float z, float[] coords, int position) { + protected void unproject(float x, float y, float[] coords, int position) { mv[0] = x; mv[1] = y; - mv[2] = z; - + mv[2] = -1; mUnprojMatrix.prj(mv); + double nx = mv[0]; + double ny = mv[1]; + double nz = mv[2]; - coords[position + 0] = mv[0]; - coords[position + 1] = mv[1]; + mv[0] = x; + mv[1] = y; + mv[2] = 1; + mUnprojMatrix.prj(mv); + double fx = mv[0]; + double fy = mv[1]; + double fz = mv[2]; + + double dx = fx - nx; + double dy = fy - ny; + double dz = fz - nz; + + double dist = -nz / dz; + + coords[position + 0] = (float) (nx + dist * dx); + coords[position + 1] = (float) (ny + dist * dy); } /** @@ -253,6 +232,14 @@ public class Viewport { MercatorProjection.toLongitude(mMovePoint.x)); } + protected void unprojectScreen(double x, double y, float[] out) { + /* scale to -1..1 */ + float mx = (float) (1 - (x / mWidth * 2)); + float my = (float) (1 - (y / mHeight * 2)); + + unproject(-mx, my, out, 0); + } + /** * Get the map position for x,y in screen coordinates. * @@ -260,11 +247,7 @@ public class Viewport { * @param y screen coordinate */ public void fromScreenPoint(double x, double y, Point out) { - // scale to -1..1 - float mx = (float) (1 - (x / mWidth * 2)); - float my = (float) (1 - (y / mHeight * 2)); - - unproject(-mx, my, getDepth(-my), mu, 0); + unprojectScreen(x, y, mu); double cs = mPos.scale * Tile.SIZE; double cx = mPos.x * cs;