package com.almalence.plugins.vf.gyro;
import com.almalence.plugins.capture.panoramaaugmented.AugmentedRotationListener.AugmentedRotationReceiver;
import com.almalence.plugins.capture.panoramaaugmented.Vector3d;
public class AugmentedSurfaceView implements AugmentedRotationReceiver
{
private final Vector3d currentVector = new Vector3d();
private final Vector3d topVector = new Vector3d(0.0f, 0.0f, 1.0f);
private final Vector3d sideVector = new Vector3d(0.0f, 1.0f, 0.0f);
private GyroVFPlugin gyro;
private final float[] transform = new float[16];
private float radius;
public AugmentedSurfaceView(GyroVFPlugin gyro)
{
this.gyro = gyro;
}
public void reset(int width, int height, float verticalViewAngleR)
{
float halfHeight = height / 2;
if (verticalViewAngleR == 0)
verticalViewAngleR = 45;
// this is the radius to the center of a frame
this.radius = (float) (halfHeight / Math.tan(Math.toRadians(verticalViewAngleR / 2.0f)));
}
@Override
public void onRotationChanged(float[] transform)
{
synchronized (this.transform)
{
if (transform.length == 16)
{
System.arraycopy(transform, 0, this.transform, 0, 16);
} else if (transform.length == 9)
{
System.arraycopy(transform, 0, this.transform, 0, 3);
System.arraycopy(transform, 3, this.transform, 4, 3);
System.arraycopy(transform, 6, this.transform, 8, 3);
this.transform[3] = 0;
this.transform[7] = 0;
this.transform[11] = 0;
this.transform[12] = 0;
this.transform[13] = 0;
this.transform[14] = 0;
this.transform[15] = 1;
} else
{
throw new RuntimeException();
}
synchronized (this.topVector)
{
this.topVector.x = this.transform[1];
this.topVector.y = this.transform[5];
this.topVector.z = this.transform[9];
}
synchronized (this.sideVector)
{
this.sideVector.x = this.transform[0];
this.sideVector.y = this.transform[4];
this.sideVector.z = this.transform[8];
}
synchronized (this.currentVector)
{
this.currentVector.x = -this.radius * this.transform[2];
this.currentVector.y = -this.radius * this.transform[6];
this.currentVector.z = -this.radius * this.transform[10];
}
}
}
public float getVerticalHorizonErrorAngle()
{
final Vector3d top;
final Vector3d dir;
synchronized (this.topVector)
{
top = new Vector3d(this.topVector);
}
synchronized (this.currentVector)
{
dir = new Vector3d(this.currentVector);
}
return getErrorAngle(top, dir);
}
public float getHorizontalHorizonErrorAngle()
{
final Vector3d side;
final Vector3d dir;
synchronized (this.sideVector)
{
side = new Vector3d(this.sideVector);
}
synchronized (this.currentVector)
{
dir = new Vector3d(this.currentVector);
}
return getErrorAngle(side, dir);
}
private float getErrorAngle(Vector3d top, Vector3d dir)
{
final float t = (dir.x * top.y - dir.y * top.x) / (dir.x * dir.x + dir.y * dir.y);
final Vector3d topProjection = new Vector3d(top.x + dir.y * t, top.y - dir.x * t, top.z);
final float plane_top_x_signum = Math.signum(topProjection.x) == Math.signum(dir.x) ? 1.0f : -1.0f;
final float plane_top_x = plane_top_x_signum
* (float) Math.sqrt(topProjection.x * topProjection.x + topProjection.y * topProjection.y);
final float plane_top_y = topProjection.z;
float angle;
if (Math.abs(plane_top_x) > 0.01f && Math.abs(plane_top_y) > 0.01f)
{
angle = (float) Math.asin(plane_top_x / Math.sqrt(plane_top_x * plane_top_x + plane_top_y * plane_top_y));
if (plane_top_y < 0.0f)
{
angle += Math.signum(angle) * (float) Math.PI / 2.0f;
}
} else
{
angle = 0.0f;
}
if (Math.abs(angle) > 1.6f && top.z < 0)
{
angle = (float) Math.acos(top.z);
if (top.z < 0)
{
angle -= Math.signum(angle) * (float) Math.PI;
if (plane_top_x > 0.0f)
{
angle = -angle;
}
}
}
if (Math.abs(angle) > 1.0f && top.z > 0)
{
angle = (float) Math.acos(top.z);
}
return angle;
}
public float getHorizonSideErrorAngleVertical()
{
final Vector3d side;
synchronized (this.sideVector)
{
side = new Vector3d(this.sideVector);
}
return (float) (Math.acos(side.z));
}
public float getHorizonSideErrorAngleHorizontal()
{
final Vector3d top;
synchronized (this.topVector)
{
top = new Vector3d(this.topVector);
}
return (float) (Math.acos(top.z));
}
public void onDrawFrame()
{
gyro.updateHorizonIndicator(getVerticalHorizonErrorAngle(), getHorizontalHorizonErrorAngle(),
getHorizonSideErrorAngleVertical(), getHorizonSideErrorAngleHorizontal());
}
}