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