/*
* Copyright (c) 2013 Allogy Interactive.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.hsl.txtreader;
import android.opengl.Matrix;
import android.util.Log;
public class TrackBall {
private final float TRACKBALL_RADIUS = 0.8f;
private float mFactor = 3f;
private float[] mV0, mV1;
private float[] mAxis;
private float mPhi;
private float[] mRotationMatrix;
private float[] mUnitMatrix;
private float[] mResultMatrix;
public TrackBall() {
mAxis = new float[3];
mV0 = new float[3];
mV1 = new float[3];
mPhi = 0f;
mRotationMatrix = new float[16];
setUnitMatrix(mRotationMatrix);
mUnitMatrix = new float[16];
setUnitMatrix(mUnitMatrix);
mResultMatrix = new float[16];
}
public void mapRotation(float[] p0, float[] p1) {
if (p0[0] == p1[0] && p0[1] == p1[1]) {
mPhi = 0f;
mAxis[0] = 1f;
mAxis[1] = 0f;
mAxis[2] = 0f;
} else {
map2Sphere(p0[0], p0[1], mV0);
map2Sphere(p1[0], p1[1], mV1);
vCross(mV1, mV0, mAxis);
double t = vDist(mV0, mV1) / (2.0 * TRACKBALL_RADIUS);
if (t > 1.0) {
t = 1.0;
} else if (t < -1.0) {
t = -1.0;
}
mPhi = (float)(2.0 * Math.asin(t));
vNormalize(mAxis);
}
//Rotate on unit matrix
setUnitMatrix(mUnitMatrix);
Matrix.rotateM(mUnitMatrix, 0, (float)(-1*mPhi*mFactor/Math.PI*180f), mAxis[0], mAxis[1], mAxis[2]);
//Apply to rotation matrix
Matrix.multiplyMM(mResultMatrix, 0, mUnitMatrix, 0, mRotationMatrix, 0);
mCopy(mResultMatrix, mRotationMatrix);
}
private void mCopy(float[] src, float[] des) {
for (int i=0; i<src.length; i++) {
des[i] = src[i];
}
}
private void vNormalize(float [] v) {
double dist = Math.sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
v[0] /= dist;
v[1] /= dist;
v[2] /= dist;
}
private double vDist(float[] v0, float[] v1) {
float x = v0[0] - v1[0];
float y = v0[1] - v1[1];
float z = v0[2] - v1[2];
return Math.sqrt(x*x + y*y + z*z);
}
private void vCross(float[] v0, float[] v1, float[] vOut) {
float x, y, z;
x = (v0[1] * v1[2]) - (v0[2] * v1[1]);
y = (v0[2] * v1[0]) - (v0[0] * v1[2]);
z = (v0[0] * v1[1]) - (v0[1] * v1[0]);
vOut[0] = x;
vOut[1] = y;
vOut[2] = z;
}
private void map2Sphere(float x, float y, float[] mappedP) {
mappedP[0] = x;
mappedP[1] = y;
float d = (float) Math.sqrt(x*x + y*y);
if (d > 1.0) {
d = 1.0f;
}
mappedP[2] = (float) Math.sqrt(1-d*d);
/*
float d, t;
d = (float) Math.sqrt(x*x + y*y);
if (d < TRACKBALL_RADIUS * 0.70710678118654752440) {
mappedP[2] = (float) Math.sqrt(TRACKBALL_RADIUS*TRACKBALL_RADIUS - d*d);
} else {
t = (float) ( TRACKBALL_RADIUS / 1.41421356237309504880);
mappedP[2] = t*t / d;
}
*/
}
private void setUnitMatrix(float[] m) {
for (int i=0; i<m.length; i++) {
m[i] = 0;
}
m[0] = 1;
m[5] = 1;
m[10] = 1;
m[15] = 1;
}
public static void logMatrix(float[] q) {
StringBuffer sb = new StringBuffer();
for (float f : q) {
sb.append(f+", ");
}
Log.i("TrackBall", sb.toString());
}
public float[] getRotationMatrix() {
//logMatrix(mRotationMatrix);
return mRotationMatrix;
}
}