Viewport screen-pivot + extent option

This commit is contained in:
Hannes Janetzek 2014-11-26 18:38:54 +01:00
parent da93f0ab72
commit 6f85e24ed9
2 changed files with 70 additions and 76 deletions

View File

@ -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();

View File

@ -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;