Cleaned up RotationVector example code to prepare for different fusion-providers.

This commit is contained in:
Alexander Pacha
2013-12-15 15:45:33 +01:00
parent 9340efd466
commit 83b7bd7883
7 changed files with 243 additions and 98 deletions

View File

@@ -14,7 +14,7 @@
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="org.hitlabnz.sensor_fusion_demo.RotationVector"
android:name="org.hitlabnz.sensor_fusion_demo.MainActivity"
android:label="@string/title_main_activity"
android:screenOrientation="nosensor" >
<intent-filter>

View File

@@ -7,7 +7,7 @@ import java.nio.FloatBuffer;
import javax.microedition.khronos.opengles.GL10;
/**
* A simple cube that is used for drawing the current rotation of the device
* A simple colour-cube that is used for drawing the current rotation of the device
*
*/
public class Cube {
@@ -24,6 +24,9 @@ public class Cube {
*/
private ByteBuffer mIndexBuffer;
/**
* Initialises a new instance of the cube
*/
public Cube() {
final float vertices[] = { -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1, };
@@ -50,6 +53,11 @@ public class Cube {
mIndexBuffer.position(0);
}
/**
* Draws this cube of the given GL-Surface
*
* @param gl The GL-Surface this cube should be drawn upon.
*/
public void draw(GL10 gl) {
gl.glEnable(GL10.GL_CULL_FACE);
gl.glFrontFace(GL10.GL_CW);

View File

@@ -0,0 +1,96 @@
package org.hitlabnz.sensor_fusion_demo;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import org.hitlabnz.sensor_fusion_demo.orientationProvider.OrientationProvider;
import android.opengl.GLSurfaceView;
/**
* Class that implements the rendering of a cube with the current rotation of the device that is provided by a
* OrientationProvider
*
* @author Alexander Pacha
*
*/
public class CubeRenderer implements GLSurfaceView.Renderer {
/**
* The colour-cube that is drawn repeatedly
*/
private Cube mCube;
/**
* The current provider of the device orientation.
*/
private OrientationProvider orientationProvider = null;
/**
* Initialises a new CubeRenderer
*/
public CubeRenderer() {
mCube = new Cube();
}
/**
* Sets the orientationProvider of this renderer. Use this method to change which sensor fusion should be currently
* used for rendering the cube. Simply exchange it with another orientationProvider and the cube will be rendered
* with another approach.
*
* @param orientationProvider The new orientation provider that delivers the current orientation of the device
*/
public void setOrientationProvider(OrientationProvider orientationProvider) {
this.orientationProvider = orientationProvider;
}
/**
* Perform the actual rendering of the cube for each frame
*
* @param gl The surface on which the cube should be rendered
*/
public void onDrawFrame(GL10 gl) {
// clear screen
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
// set-up modelview matrix
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
gl.glTranslatef(0, 0, -3.0f);
if (orientationProvider != null) {
// Get the rotation from the current orientationProvider
gl.glMultMatrixf(orientationProvider.getRotationMatrix(), 0);
}
// draw our object
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
mCube.draw(gl);
}
/**
* Update view-port with the new surface
*
* @param gl the surface
* @param width new width
* @param height new height
*/
public void onSurfaceChanged(GL10 gl, int width, int height) {
// set view-port
gl.glViewport(0, 0, width, height);
// set projection matrix
float ratio = (float) width / height;
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// dither is enabled by default, we don't need it
gl.glDisable(GL10.GL_DITHER);
// clear screen in black
gl.glClearColor(0, 0, 0, 1);
}
}

View File

@@ -11,6 +11,9 @@
package org.hitlabnz.sensor_fusion_demo;
import org.hitlabnz.sensor_fusion_demo.orientationProvider.OrientationProvider;
import org.hitlabnz.sensor_fusion_demo.orientationProvider.RotationVectorProvider;
import android.app.Activity;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
@@ -27,16 +30,29 @@ import android.os.Bundle;
* @see SensorManager
*
*/
public class RotationVector extends Activity {
public class MainActivity extends Activity {
/**
* The surface that will be drawn upon
*/
private GLSurfaceView mGLSurfaceView;
private SensorFuser mRenderer;
/**
* The class that renders the cube
*/
private CubeRenderer mRenderer;
/**
* The current orientation provider that delivers device orientation.
*/
private OrientationProvider currentOrientationProvider;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Initialise the orientationProvider
currentOrientationProvider = new RotationVectorProvider((SensorManager) getSystemService(SENSOR_SERVICE));
// Create our Preview view and set it as the content of our Activity
mRenderer = new SensorFuser((SensorManager) getSystemService(SENSOR_SERVICE));
mRenderer = new CubeRenderer();
mRenderer.setOrientationProvider(currentOrientationProvider);
mGLSurfaceView = new GLSurfaceView(this);
mGLSurfaceView.setRenderer(mRenderer);
setContentView(mGLSurfaceView);
@@ -47,7 +63,7 @@ public class RotationVector extends Activity {
// Ideally a game should implement onResume() and onPause()
// to take appropriate action when the activity looses focus
super.onResume();
mRenderer.start();
currentOrientationProvider.start();
mGLSurfaceView.onResume();
}
@@ -56,7 +72,7 @@ public class RotationVector extends Activity {
// Ideally a game should implement onResume() and onPause()
// to take appropriate action when the activity looses focus
super.onPause();
mRenderer.stop();
currentOrientationProvider.stop();
mGLSurfaceView.onPause();
}
}

View File

@@ -1,91 +0,0 @@
package org.hitlabnz.sensor_fusion_demo;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.opengl.GLSurfaceView;
public class SensorFuser implements GLSurfaceView.Renderer, SensorEventListener {
private Cube mCube;
private Sensor mRotationVectorSensor;
private final float[] mRotationMatrix = new float[16];
private SensorManager mSensorManager;
public SensorFuser(SensorManager sensorManager) {
mSensorManager = sensorManager;
// find the rotation-vector sensor
mRotationVectorSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);
mCube = new Cube();
// initialize the rotation matrix to identity
mRotationMatrix[0] = 1;
mRotationMatrix[4] = 1;
mRotationMatrix[8] = 1;
mRotationMatrix[12] = 1;
}
public void start() {
// enable our sensor when the activity is resumed, ask for
// 10 ms updates.
mSensorManager.registerListener(this, mRotationVectorSensor, 10000);
}
public void stop() {
// make sure to turn our sensor off when the activity is paused
mSensorManager.unregisterListener(this);
}
public void onSensorChanged(SensorEvent event) {
// we received a sensor event. it is a good practice to check
// that we received the proper event
if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) {
// convert the rotation-vector to a 4x4 matrix. the matrix
// is interpreted by Open GL as the inverse of the
// rotation-vector, which is what we want.
SensorManager.getRotationMatrixFromVector(mRotationMatrix, event.values);
}
}
public void onDrawFrame(GL10 gl) {
// clear screen
gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
// set-up modelview matrix
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
gl.glTranslatef(0, 0, -3.0f);
gl.glMultMatrixf(mRotationMatrix, 0);
// draw our object
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
mCube.draw(gl);
}
public void onSurfaceChanged(GL10 gl, int width, int height) {
// set view-port
gl.glViewport(0, 0, width, height);
// set projection matrix
float ratio = (float) width / height;
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// dither is enabled by default, we don't need it
gl.glDisable(GL10.GL_DITHER);
// clear screen in black
gl.glClearColor(0, 0, 0, 1);
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
}

View File

@@ -0,0 +1,33 @@
/**
*
*/
package org.hitlabnz.sensor_fusion_demo.orientationProvider;
/**
* Classes implementing this interface provide an orientation of the device either by directly accessing hardware, using
* Android sensor fusion or fusing sensors itself.
*
* The orientation can be provided as rotation matrix or quaternion.
*
* @author Alexander Pacha
*
*/
public interface OrientationProvider {
/**
*
* @return Returns the current rotation of the device in the rotation matrix format
*/
public float[] getRotationMatrix();
/**
* Starts the sensor fusion (e.g. when resuming the activity)
*/
public void start();
/**
* Stops the sensor fusion (e.g. when pausing/suspending the activity)
*/
public void stop();
}

View File

@@ -0,0 +1,83 @@
package org.hitlabnz.sensor_fusion_demo.orientationProvider;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
/**
* The orientation provider that delivers the current orientation from the {@link Sensor#TYPE_ROTATION_VECTOR Android
* Rotation Vector sensor}.
*
* @author Alexander Pacha
*
*/
public class RotationVectorProvider implements SensorEventListener, OrientationProvider {
/**
* The rotation vector sensor that is being used for this provider to get device orientation
*/
private Sensor rotationVectorSensor;
/**
* The matrix that holds the current rotation
*/
private final float[] currentOrientationRotationMatrix = new float[16];
/**
* The sensor manager for accessing android sensors
*/
private SensorManager sensorManager;
/**
* Initialises a new RotationVectorProvider
*
* @param sensorManager The android sensor manager
*/
public RotationVectorProvider(SensorManager sensorManager) {
this.sensorManager = sensorManager;
// find the rotation-vector sensor
rotationVectorSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);
// initialize the rotation matrix to identity
currentOrientationRotationMatrix[0] = 1;
currentOrientationRotationMatrix[4] = 1;
currentOrientationRotationMatrix[8] = 1;
currentOrientationRotationMatrix[12] = 1;
}
@Override
public void start() {
// enable our sensor when the activity is resumed, ask for
// 10 ms updates.
sensorManager.registerListener(this, rotationVectorSensor, 10000);
}
@Override
public void stop() {
// make sure to turn our sensor off when the activity is paused
sensorManager.unregisterListener(this);
}
@Override
public void onSensorChanged(SensorEvent event) {
// we received a sensor event. it is a good practice to check
// that we received the proper event
if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) {
// convert the rotation-vector to a 4x4 matrix. the matrix
// is interpreted by Open GL as the inverse of the
// rotation-vector, which is what we want.
SensorManager.getRotationMatrixFromVector(currentOrientationRotationMatrix, event.values);
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
@Override
public float[] getRotationMatrix() {
return currentOrientationRotationMatrix;
}
}