Viewport screen-pivot + extent option
This commit is contained in:
parent
da93f0ab72
commit
6f85e24ed9
@ -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();
|
||||
|
@ -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;
|
||||
|
Loading…
x
Reference in New Issue
Block a user