finally got that z-value for un-projection right (=

- add more matrix utilities
This commit is contained in:
Hannes Janetzek 2013-01-11 20:01:55 +01:00
parent a8bcc59e25
commit 4acd9a492f
2 changed files with 127 additions and 157 deletions

View File

@ -189,24 +189,45 @@ public class GlUtils {
return c; return c;
} }
private final static float[] mIdentity = {
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1 };
public static void setTileMatrix(float[] matrix, float tx, float ty, float s) { public static void setTileMatrix(float[] matrix, float tx, float ty, float s) {
System.arraycopy(mIdentity, 0, matrix, 0, 16);
// scale tile relative to map scale // scale tile relative to map scale
matrix[0] = matrix[5] = s / GLRenderer.COORD_MULTIPLIER; matrix[0] = matrix[5] = s / GLRenderer.COORD_MULTIPLIER;
matrix[1] = 0;
matrix[2] = 0;
matrix[3] = 0;
matrix[4] = 0;
matrix[6] = 0;
matrix[7] = 0;
matrix[8] = 0;
matrix[9] = 0;
matrix[10] = 1;
matrix[11] = 0;
// translate relative to map center // translate relative to map center
matrix[12] = tx * s; matrix[12] = tx * s;
matrix[13] = ty * s; matrix[13] = ty * s;
matrix[14] = 0; }
matrix[15] = 1;
public static void setTranslation(float[] matrix, float x, float y, float z) {
System.arraycopy(mIdentity, 0, matrix, 0, 16);
matrix[12] = x;
matrix[13] = y;
matrix[14] = z;
}
public static void setMatrix(float[] matrix, float tx, float ty, float scale) {
System.arraycopy(mIdentity, 0, matrix, 0, 16);
matrix[12] = tx;
matrix[13] = ty;
matrix[0] = scale;
matrix[5] = scale;
//matrix[10] = scale;
}
public static void setIdentity(float[] matrix) {
System.arraycopy(mIdentity, 0, matrix, 0, 16);
}
public static void setScaleM(float[] matrix, float sx, float sy, float sz) {
System.arraycopy(mIdentity, 0, matrix, 0, 16);
matrix[0] = sx;
matrix[5] = sy;
matrix[10] = sz;
} }
} }

View File

@ -26,7 +26,9 @@ import org.oscim.core.MapPosition;
import org.oscim.core.MercatorProjection; import org.oscim.core.MercatorProjection;
import org.oscim.core.Tile; import org.oscim.core.Tile;
import org.oscim.utils.FastMath; import org.oscim.utils.FastMath;
import org.oscim.utils.GeometryUtils;
import org.oscim.utils.GeometryUtils.Point2D; import org.oscim.utils.GeometryUtils.Point2D;
import org.oscim.utils.GlUtils;
import android.graphics.Point; import android.graphics.Point;
import android.opengl.Matrix; import android.opengl.Matrix;
@ -47,7 +49,7 @@ public class MapViewPosition {
public final static int MAX_ZOOMLEVEL = 17; public final static int MAX_ZOOMLEVEL = 17;
public final static int MIN_ZOOMLEVEL = 2; public final static int MIN_ZOOMLEVEL = 2;
private final static float MAX_ANGLE = 42; private final static float MAX_ANGLE = 50;
private final MapView mMapView; private final MapView mMapView;
@ -87,56 +89,32 @@ public class MapViewPosition {
private float[] mRotMatrix = new float[16]; private float[] mRotMatrix = new float[16];
private float[] mTmpMatrix = new float[16]; private float[] mTmpMatrix = new float[16];
// only use in synchronized functions! // temporary vars: only use in synchronized functions!
Point2D mMovePoint = new Point2D(); private Point2D mMovePoint = new Point2D();
private float[] mv = { 0, 0, 0, 1 };
private float[] mu = { 0, 0, 0, 1 };
private float[] mBBoxCoords = new float[8];
private static float mHeight, mWidth; private float mHeight, mWidth;
// public final static float VIEW_SCALE = 1 / 4f;
// public final static float VIEW_DISTANCE = 2f;
// public final static float VIEW_NEAR = 1;
// public final static float VIEW_FAR = 4;
// public final static float VIEW_SCALE = 1 / 3f;
// public final static float VIEW_DISTANCE = 2.7f;
// public final static float VIEW_NEAR = 2;
// public final static float VIEW_FAR = 4;
public final static float VIEW_SCALE = 1 / 4f;
public final static float VIEW_DISTANCE = 3.0f; public final static float VIEW_DISTANCE = 3.0f;
public final static float VIEW_NEAR = 2; public final static float VIEW_NEAR = 2;
public final static float VIEW_FAR = 8; public final static float VIEW_FAR = 7;
// scale map plane at VIEW_DISTANCE to near plane
public final static float VIEW_SCALE = (VIEW_NEAR / VIEW_DISTANCE) * 0.5f;
void setViewport(int width, int height) { void setViewport(int width, int height) {
float sw = VIEW_SCALE; float s = VIEW_SCALE;
float sh = VIEW_SCALE;
float aspect = height / (float) width; float aspect = height / (float) width;
Matrix.frustumM(mProjMatrix, 0, -1 * sw, 1 * sw, Matrix.frustumM(mProjMatrix, 0, -s, s,
aspect * sh, -aspect * sh, VIEW_NEAR, VIEW_FAR); aspect * s, -aspect * s, VIEW_NEAR, VIEW_FAR);
Matrix.setIdentityM(mTmpMatrix, 0);
Matrix.translateM(mTmpMatrix, 0, 0, 0, -VIEW_DISTANCE);
GlUtils.setTranslation(mTmpMatrix, 0, 0, -VIEW_DISTANCE);
Matrix.multiplyMM(mProjMatrix, 0, mProjMatrix, 0, mTmpMatrix, 0); Matrix.multiplyMM(mProjMatrix, 0, mProjMatrix, 0, mTmpMatrix, 0);
Matrix.invertM(mProjMatrixI, 0, mProjMatrix, 0); Matrix.invertM(mProjMatrixI, 0, mProjMatrix, 0);
mv[0] = 0;
mv[1] = 1;
mv[2] = 0;
mv[3] = 1;
Matrix.multiplyMV(mv, 0, mProjMatrixI, 0, mv, 0);
Log.d(TAG, " " + mv[0] + " " + mv[1] + " " + mv[2]);
Log.d(TAG, " " + mv[0] / mv[3] + " " + mv[1] / mv[3] + " " + mv[2] / mv[3]);
mv[0] = 0;
mv[1] = 1;
mv[2] = 1;
mv[3] = 1;
Matrix.multiplyMV(mv, 0, mProjMatrixI, 0, mv, 0);
Log.d(TAG, " " + mv[0] + " " + mv[1] + " " + mv[2]);
Log.d(TAG, " " + mv[0] / mv[3] + " " + mv[1] / mv[3] + " " + mv[2] / mv[3]);
mHeight = height; mHeight = height;
mWidth = width; mWidth = width;
@ -174,69 +152,86 @@ public class MapViewPosition {
if (coords == null) if (coords == null)
return true; return true;
// float tilt = getZ(1); float t = getZ(1);
float t2 = getZ(-1);
float t = getZ2(1); unproject(1, -1, t, coords, 0); // top-right
float t2 = getZ2(-1); unproject(-1, -1, t, coords, 2); // top-left
//Log.d(TAG, "t:" + mTilt + " z: " + tilt + " -> " + t + " " + t2); unproject(-1, 1, t2, coords, 4); // bottom-left
// unproject(1, 1, t2, coords, 6); // bottom-right
// unproject(-1, 1, tilt, coords, 0); // bottom-left
// unproject(1, 1, tilt, coords, 2); // bottom-right
// unproject(1, -1, -tilt, coords, 4); // top-right
// unproject(-1, -1, -tilt, coords, 6); // top-left
unproject2(-1, 1, t2, coords, 4); // bottom-left
unproject2(1, 1, t2, coords, 6); // bottom-right
unproject2(1, -1, t, coords, 0); // top-right
unproject2(-1, -1, t, coords, 2); // top-left
// Log.d(TAG, "" + coords[0] + ":" + coords[1] + ", " + coords[2] + ":" + coords[3] + ", "
// + ", " + coords[4] + ":" + coords[5] + ", " + ", " + coords[6] + ":" + coords[7]);
return true; return true;
} }
private float getZ2(float y) { public static byte calcLinesIntersect(
double ax2, double ay2,
double bx1, double by1,
double bx2, double by2,
GeometryUtils.Point2D point)
{
double ua_numr = (bx2 - bx1) * (-by1) - (by2 - by1) * (-bx1);
double denr = (by2 - by1) * (ax2) - (bx2 - bx1) * (ay2);
double ua = ua_numr / denr;
point.x = ua * ax2;
point.y = ua * ay2;
return 1;
}
// get the z-value of the map-plane for a point on screen
private float getZ(float y) {
// calculate the intersection of a ray from
// camera origin and the map plane
// origin is moved by VIEW_DISTANCE
double cx = VIEW_DISTANCE;
// 'height' of the ray
double ry = y * (mHeight / mWidth) * 0.5f;
// tilt of the plane (center is kept on x = 0)
double t = Math.toRadians(mTilt);
double px = y * Math.sin(t);
double py = y * Math.cos(t);
double ua = 1 + (px * ry) / (py * cx);
mv[0] = 0; mv[0] = 0;
mv[1] = y; mv[1] = (float) (ry / ua);
mv[2] = -0.1f; //FIXME! please mv[2] = (float) (cx - cx / ua);
mv[3] = 1; mv[3] = 1;
Matrix.setRotateM(mTmpMatrix, 0, mTilt, 1, 0, 0); // GeometryUtils.calcLinesIntersect(
Matrix.multiplyMV(mv, 0, mTmpMatrix, 0, mv, 0); // // point at view origin
// VIEW_DISTANCE, 0, 0, y * 0.5,
// // point at upper lower edge of tilted plane
// 0, 0, -y * Math.sin(t), y * Math.cos(t),
// mMovePoint);
// mv[0] = 0;
// mv[1] = (float) mMovePoint.y;
// mv[2] = (float) mMovePoint.x;
// mv[3] = 1;
Matrix.multiplyMV(mv, 0, mProjMatrix, 0, mv, 0); Matrix.multiplyMV(mv, 0, mProjMatrix, 0, mv, 0);
//d = d / (VIEW_FAR - VIEW_NEAR); return mv[2] / mv[3];
//Log.d(TAG, " > " + mv[2] / mv[3] + " (" + mv[2] + " " + mv[3] + ")");
float d = mv[2] / mv[3];
Matrix.multiplyMV(mv, 0, mUnprojMatrix, 0, mv, 0);
//Log.d(TAG, " < " + mv[2] / mv[3] + " (" + mv[2] + " " + mv[3] + ")");
return d;
} }
private void unproject2(float x, float y, float z, float[] coords, int position) { private void unproject(float x, float y, float z, float[] coords, int position) {
mv[0] = x; mv[0] = x;
mv[1] = y; mv[1] = y;
mv[2] = z; mv[2] = z;
mv[3] = 1; mv[3] = 1;
//float a = (float) Math.sqrt(x * x + y * y + z * z + 1);
// mv[0] /= a;
// mv[1] /= a;
// mv[2] /= a;
//mv[3] = a;
Matrix.multiplyMV(mv, 0, mUnprojMatrix, 0, mv, 0); Matrix.multiplyMV(mv, 0, mUnprojMatrix, 0, mv, 0);
if (mv[3] != 0) { if (mv[3] != 0) {
coords[position] = mv[0] / mv[3]; coords[position + 0] = mv[0] / mv[3];
coords[position + 1] = (mv[1] / mv[3]); coords[position + 1] = mv[1] / mv[3];
} else { } else {
// else what? coords[position + 0] = 0;
Log.d(TAG, "uproject failed"); coords[position + 1] = 0;
Log.d(TAG, "XXX unproject failed");
} }
} }
@ -275,19 +270,13 @@ public class MapViewPosition {
float[] coords = mBBoxCoords; float[] coords = mBBoxCoords;
// float tilt = getZ(1);
float t = getZ(1); float t = getZ(1);
float t2 = getZ(-1); float t2 = getZ(-1);
// unproject(-1, 1, -tilt, coords, 0); // top-left unproject(1, -1, t, coords, 0); // top-right
// unproject(1, 1, -tilt, coords, 2); // top-right unproject(-1, -1, t, coords, 2); // top-left
// unproject(1, -1, tilt, coords, 4); // bottom-right unproject(-1, 1, t2, coords, 4); // bottom-left
// unproject(-1, -1, tilt, coords, 6); // bottom-left unproject(1, 1, t2, coords, 6); // bottom-right
unproject2(-1, 1, t2, coords, 4); // bottom-left
unproject2(1, 1, t2, coords, 6); // bottom-right
unproject2(1, -1, t, coords, 0); // top-right
unproject2(-1, -1, t, coords, 2); // top-left
byte z = mZoomLevel; byte z = mZoomLevel;
double dx, dy; double dx, dy;
@ -316,23 +305,11 @@ public class MapViewPosition {
} }
} }
return new BoundingBox(minLat, minLon, maxLat, maxLon); BoundingBox bbox = new BoundingBox(minLat, minLon, maxLat, maxLon);
}
private float[] mv = { 0, 0, 0, 1 }; Log.d(">>>", "getScreenBoundingBox " + bbox);
private float[] mu = { 0, 0, 0, 1 };
private float[] mBBoxCoords = new float[8];
/* get the depth-value of the map for the current tilt, approximately. return bbox;
* needed to un-project a point on screen to the position on the map. not
* so sure about this, but at least somehow works. */
private float getZ(float y) {
return (float) Math.sin(Math.toRadians(mTilt))
//* 2.2f // for dist = 1
//* 1.3f // for dist = 2
//* 0.8f // for dist = 4
* 0.5f
* (mHeight / mWidth) * y;
} }
/** /**
@ -349,7 +326,7 @@ public class MapViewPosition {
float mx = ((mWidth / 2) - x) / (mWidth / 2); float mx = ((mWidth / 2) - x) / (mWidth / 2);
float my = ((mHeight / 2) - y) / (mHeight / 2); float my = ((mHeight / 2) - y) / (mHeight / 2);
unproject2(-mx, my, getZ2(-my), mu, 0); unproject(-mx, my, getZ(-my), mu, 0);
out.x = (int) (mPosX + mu[0] / mScale); out.x = (int) (mPosX + mu[0] / mScale);
out.y = (int) (mPosY + mu[1] / mScale); out.y = (int) (mPosY + mu[1] / mScale);
@ -368,7 +345,7 @@ public class MapViewPosition {
float mx = ((mWidth / 2) - x) / (mWidth / 2); float mx = ((mWidth / 2) - x) / (mWidth / 2);
float my = ((mHeight / 2) - y) / (mHeight / 2); float my = ((mHeight / 2) - y) / (mHeight / 2);
unproject2(-mx, my, getZ2(-my), mu, 0); unproject(-mx, my, getZ(-my), mu, 0);
double dx = mPosX + mu[0] / mScale; double dx = mPosX + mu[0] / mScale;
double dy = mPosY + mu[1] / mScale; double dy = mPosY + mu[1] / mScale;
@ -432,32 +409,14 @@ public class MapViewPosition {
// return out; // return out;
// } // }
private void unproject(float x, float y, float z, float[] coords, int position) {
mv[0] = x;
mv[1] = y;
// -1f when near plane is 1 and map is on near plane..
mv[2] = z + 0.4f;
mv[3] = 1;
Matrix.multiplyMV(mv, 0, mUnprojMatrix, 0, mv, 0);
if (mv[3] != 0) {
coords[position] = mv[0] / mv[3];
coords[position + 1] = mv[1] / mv[3];
} else {
// else what?
Log.d(TAG, "uproject failed");
}
}
private void updateMatrix() { private void updateMatrix() {
// - view matrix // --- view matrix
// 1. scale to window coordinates // 1. scale to window coordinates
// 2. rotate // 2. rotate
// 3. tilt // 3. tilt
// - projection matrix // --- projection matrix
// 4. translate to near-plane // 4. translate to VIEW_DISTANCE
// 5. apply projection // 5. apply projection
Matrix.setRotateM(mRotMatrix, 0, mRotation, 0, 0, 1); Matrix.setRotateM(mRotMatrix, 0, mRotation, 0, 0, 1);
@ -470,35 +429,25 @@ public class MapViewPosition {
Matrix.multiplyMM(mRotMatrix, 0, mTmpMatrix, 0, mRotMatrix, 0); Matrix.multiplyMM(mRotMatrix, 0, mTmpMatrix, 0, mRotMatrix, 0);
// scale to window coordinates // scale to window coordinates
Matrix.setIdentityM(mTmpMatrix, 0); GlUtils.setScaleM(mTmpMatrix, 1 / mWidth, 1 / mWidth, 1);
Matrix.scaleM(mTmpMatrix, 0, 1f / mWidth, 1f / mWidth, 1);
Matrix.multiplyMM(mViewMatrix, 0, mRotMatrix, 0, mTmpMatrix, 0); Matrix.multiplyMM(mViewMatrix, 0, mRotMatrix, 0, mTmpMatrix, 0);
// // move to near plane //--- unproject matrix:
// Matrix.setIdentityM(mTmpMatrix, 0); // Matrix.multiplyMM(mTmpMatrix, 0, mProjMatrix, 0, mViewMatrix, 0);
// Matrix.translateM(mTmpMatrix, 0, 0, 0, -VIEW_DISTANCE); // Matrix.invertM(mUnprojMatrix, 0, mTmpMatrix, 0);
// Matrix.multiplyMM(mViewMatrix, 0, mTmpMatrix, 0, mViewMatrix, 0);
// get unproject matrix:
Matrix.setIdentityM(mUnprojMatrix, 0);
// inverse scale // inverse scale
Matrix.scaleM(mUnprojMatrix, 0, mWidth, mWidth, 1); GlUtils.setScaleM(mUnprojMatrix, mWidth, mWidth, 1);
// inverse rotation // inverse rotation and tilt
Matrix.transposeM(mTmpMatrix, 0, mRotMatrix, 0); Matrix.transposeM(mTmpMatrix, 0, mRotMatrix, 0);
// (AB)^-1 = B^-1*A^-1 // (AB)^-1 = B^-1*A^-1, unapply scale, tilt and rotation
Matrix.multiplyMM(mTmpMatrix, 0, mUnprojMatrix, 0, mTmpMatrix, 0); Matrix.multiplyMM(mTmpMatrix, 0, mUnprojMatrix, 0, mTmpMatrix, 0);
// unapply projection, tilt, rotate and scale // (AB)^-1 = B^-1*A^-1, unapply projection
// (AB)^-1 = B^-1*A^-1
Matrix.multiplyMM(mUnprojMatrix, 0, mTmpMatrix, 0, mProjMatrixI, 0); Matrix.multiplyMM(mUnprojMatrix, 0, mTmpMatrix, 0, mProjMatrixI, 0);
Matrix.multiplyMM(mTmpMatrix, 0, mProjMatrix, 0, mViewMatrix, 0);
Matrix.invertM(mUnprojMatrix, 0, mTmpMatrix, 0);
} }
/** @return true if this MapViewPosition is valid, false otherwise. */ /** @return true if this MapViewPosition is valid, false otherwise. */