All Downloads are FREE. Search and download functionalities are using the official Maven repository.

sim.android.hardware.SensorManager Maven / Gradle / Ivy

The newest version!
package sim.android.hardware;

/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * 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.
 */
import android.hardware.Sensor;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import sim.android.hardware.service.impl.SensorEventService;

public class SensorManager {

	private static final String TAG = "SensorManager";
	private static final float[] mTempMatrix = new float[16];

	@Deprecated
	public static final int SENSOR_ORIENTATION = 1 << 0;

	@Deprecated
	public static final int SENSOR_ACCELEROMETER = 1 << 1;
	
	@Deprecated
	public static final int SENSOR_TEMPERATURE = 1 << 2;
	
	@Deprecated
	public static final int SENSOR_MAGNETIC_FIELD = 1 << 3;
	
	@Deprecated
	public static final int SENSOR_LIGHT = 1 << 4;
	
	@Deprecated
	public static final int SENSOR_PROXIMITY = 1 << 5;
	
	@Deprecated
	public static final int SENSOR_TRICORDER = 1 << 6;
	
	@Deprecated
	public static final int SENSOR_ORIENTATION_RAW = 1 << 7;
	
	@Deprecated
	public static final int SENSOR_ALL = 0x7F;
	
	@Deprecated
	public static final int SENSOR_MIN = SENSOR_ORIENTATION;
	/**
	 * Largest sensor ID
	 *
	 * @deprecated use {@link android.hardware.Sensor Sensor} instead.
	 */
	@Deprecated
	public static final int SENSOR_MAX = ((SENSOR_ALL + 1) >> 1);
	/**
	 * Index of the X value in the array returned by
	 * {@link android.hardware.SensorListener#onSensorChanged}
	 *
	 * @deprecated use {@link android.hardware.Sensor Sensor} instead.
	 */
	@Deprecated
	public static final int DATA_X = 0;
	/**
	 * Index of the Y value in the array returned by
	 * {@link android.hardware.SensorListener#onSensorChanged}
	 *
	 * @deprecated use {@link android.hardware.Sensor Sensor} instead.
	 */
	@Deprecated
	public static final int DATA_Y = 1;
	
	@Deprecated
	public static final int DATA_Z = 2;
	
	@Deprecated
	public static final int RAW_DATA_INDEX = 3;
	
	@Deprecated
	public static final int RAW_DATA_X = 3;
	
	@Deprecated
	public static final int RAW_DATA_Y = 4;
	
	@Deprecated
	public static final int RAW_DATA_Z = 5;
	/**
	 * Standard gravity (g) on Earth. This value is equivalent to 1G
	 */
	public static final float STANDARD_GRAVITY = 9.80665f;
	/**
	 * Sun's gravity in SI units (m/s^2)
	 */
	public static final float GRAVITY_SUN = 275.0f;
	/**
	 * Mercury's gravity in SI units (m/s^2)
	 */
	public static final float GRAVITY_MERCURY = 3.70f;
	/**
	 * Venus' gravity in SI units (m/s^2)
	 */
	public static final float GRAVITY_VENUS = 8.87f;
	/**
	 * Earth's gravity in SI units (m/s^2)
	 */
	public static final float GRAVITY_EARTH = 9.80665f;
	/**
	 * The Moon's gravity in SI units (m/s^2)
	 */
	public static final float GRAVITY_MOON = 1.6f;
	/**
	 * Mars' gravity in SI units (m/s^2)
	 */
	public static final float GRAVITY_MARS = 3.71f;
	/**
	 * Jupiter's gravity in SI units (m/s^2)
	 */
	public static final float GRAVITY_JUPITER = 23.12f;
	/**
	 * Saturn's gravity in SI units (m/s^2)
	 */
	public static final float GRAVITY_SATURN = 8.96f;
	/**
	 * Uranus' gravity in SI units (m/s^2)
	 */
	public static final float GRAVITY_URANUS = 8.69f;
	/**
	 * Neptune's gravity in SI units (m/s^2)
	 */
	public static final float GRAVITY_NEPTUNE = 11.0f;
	/**
	 * Pluto's gravity in SI units (m/s^2)
	 */
	public static final float GRAVITY_PLUTO = 0.6f;
	/**
	 * Gravity (estimate) on the first Death Star in Empire units (m/s^2)
	 */
	public static final float GRAVITY_DEATH_STAR_I = 0.000000353036145f;
	/**
	 * Gravity on the island
	 */
	public static final float GRAVITY_THE_ISLAND = 4.815162342f;
	/**
	 * Maximum magnetic field on Earth's surface
	 */
	public static final float MAGNETIC_FIELD_EARTH_MAX = 60.0f;
	/**
	 * Minimum magnetic field on Earth's surface
	 */
	public static final float MAGNETIC_FIELD_EARTH_MIN = 30.0f;
	/**
	 * Standard atmosphere, or average sea-level pressure in hPa (millibar)
	 */
	public static final float PRESSURE_STANDARD_ATMOSPHERE = 1013.25f;
	/**
	 * Maximum luminance of sunlight in lux
	 */
	public static final float LIGHT_SUNLIGHT_MAX = 120000.0f;
	/**
	 * luminance of sunlight in lux
	 */
	public static final float LIGHT_SUNLIGHT = 110000.0f;
	/**
	 * luminance in shade in lux
	 */
	public static final float LIGHT_SHADE = 20000.0f;
	/**
	 * luminance under an overcast sky in lux
	 */
	public static final float LIGHT_OVERCAST = 10000.0f;
	/**
	 * luminance at sunrise in lux
	 */
	public static final float LIGHT_SUNRISE = 400.0f;
	/**
	 * luminance under a cloudy sky in lux
	 */
	public static final float LIGHT_CLOUDY = 100.0f;
	/**
	 * luminance at night with full moon in lux
	 */
	public static final float LIGHT_FULLMOON = 0.25f;
	/**
	 * luminance at night with no moon in lux
	 */
	public static final float LIGHT_NO_MOON = 0.001f;
	/**
	 * get sensor data as fast as possible
	 */
	public static final int SENSOR_DELAY_FASTEST = 0;
	/**
	 * rate suitable for games
	 */
	public static final int SENSOR_DELAY_GAME = 1;
	/**
	 * rate suitable for the user interface
	 */
	public static final int SENSOR_DELAY_UI = 2;
	/**
	 * rate (default) suitable for screen orientation changes
	 */
	public static final int SENSOR_DELAY_NORMAL = 3;
	/**
	 * The values returned by this sensor cannot be trusted, calibration is
	 * needed or the environment doesn't allow readings
	 */
	public static final int SENSOR_STATUS_UNRELIABLE = 0;
	/**
	 * This sensor is reporting data with low accuracy, calibration with the
	 * environment is needed
	 */
	public static final int SENSOR_STATUS_ACCURACY_LOW = 1;
	

	public static final int SENSOR_STATUS_ACCURACY_MEDIUM = 2;
	

	public static final int SENSOR_STATUS_ACCURACY_HIGH = 3;
	

	public static final int AXIS_X = 1;
	

	public static final int AXIS_Y = 2;
	

	public static final int AXIS_Z = 3;
	

	public static final int AXIS_MINUS_X = AXIS_X | 0x80;
	

	public static final int AXIS_MINUS_Y = AXIS_Y | 0x80;
	

	public static final int AXIS_MINUS_Z = AXIS_Z | 0x80;

	/*-----------------------------------------------------------------------*/
	private static boolean sSensorModuleInitialized = false;
	private SensorEventService sensorEventService;
	private EventHandler mEventHandler;
	// Used within this module from outside SensorManager, don't make private
	static ArrayList mSensors = new ArrayList();
	static final ArrayList mListeners = new ArrayList();

	class FullListener {

		android.hardware.SensorEventListener sensorEventListener;
		int rate;
		Handler handler;
		android.hardware.Sensor sensor;
	}

	/**
	 *
	 */
	 public SensorManager() {
		 if (!sSensorModuleInitialized) {
			 Looper looper;
			 if ((looper = Looper.myLooper()) != null) {
				 mEventHandler = new EventHandler(looper);
			 } else if ((looper = Looper.getMainLooper()) != null) {
				 mEventHandler = new EventHandler(looper);
			 } else {
				 mEventHandler = null;
			 }
			 sSensorModuleInitialized = true;

			 // initialize the sensor list
			 mSensors = new ArrayList();

			 addAccelerometerSensor();
			 addMagneticFieldSensor();
			 addOrientationSensor();

			 sensorEventService = new SensorEventService(this, mEventHandler);
			 sensorEventService.start();
		 }
	 }

	 public List getListeners() {
		 return mListeners;
	 }

	 private void addAccelerometerSensor() {
			 synchronized (mSensors) {
				 mSensors.add(createSensor(Sensor.TYPE_ACCELEROMETER));
			 }
	 }
	 
	 private android.hardware.Sensor createSensor(int type){
		 try {
			 Constructor sensorCons = android.hardware.Sensor.class.getDeclaredConstructors()[0];
			 sensorCons.setAccessible(true);
			 android.hardware.Sensor sensor =(android.hardware.Sensor) sensorCons.newInstance(new Object[]{});
			 Field mtype= android.hardware.Sensor.class.getDeclaredField("mType");
			 mtype.setAccessible(true);
			 mtype.set(sensor, type);
			return sensor;
		 } catch (IllegalArgumentException e) {
			 // TODO Auto-generated catch block
			 e.printStackTrace();
		 } catch (IllegalAccessException e) {
			 // TODO Auto-generated catch block
			 e.printStackTrace();
		 } catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		 return null;

	 }

	 private void addMagneticFieldSensor() {
		 
		 synchronized (mSensors) {
			 mSensors.add(createSensor(Sensor.TYPE_MAGNETIC_FIELD));
		 }
	 }

	 private void addOrientationSensor() {
		 android.hardware.Sensor sensor = createSensor(Sensor.TYPE_ORIENTATION);
		 Method setRange;
		try {
			setRange = android.hardware.Sensor.class.getDeclaredMethod("setRange",Float.TYPE,Float.TYPE);
			 setRange.setAccessible(true);
			 setRange.invoke(sensor, 360.0f,1.0f);
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		 synchronized (mSensors) {
			 mSensors.add(sensor);
		 }
	 }

	 public class EventHandler extends Handler {

		 public static final int NEW_VALUE = 0;

		 public EventHandler(Looper looper) {
			 super(looper);
		 }

		 @Override
		 public void handleMessage(Message msg) {
			 switch (msg.what) {
			 case NEW_VALUE:
				 notifySensorChangedToListener((android.hardware.SensorEvent) msg.obj);
				 return;
			 default:
				 Log.e(TAG, "Unknown message type " + msg.what);
				 return;
			 }
		 }
	 }

	 public void notifySensorChangedToListener(android.hardware.SensorEvent se) {
		 System.out.println("notifySensorChangedToListener!!");
		 synchronized (mListeners) {
			 for (FullListener fl : mListeners) {
				 if (fl.sensor.getType() == se.sensor.getType()) {
					 fl.sensorEventListener.onSensorChanged(se);
				 }
			 }
		 }
	 }

	 @Deprecated
	 public int getSensors() {
		 synchronized (mSensors) {
			 int result = 0;
			 final ArrayList fullList = mSensors;
			 for (android.hardware.Sensor i : fullList) {
				 switch (i.getType()) {
				 case Sensor.TYPE_ACCELEROMETER:
					 result |= SensorManager.SENSOR_ACCELEROMETER;
					 break;
				 case Sensor.TYPE_MAGNETIC_FIELD:
					 result |= SensorManager.SENSOR_MAGNETIC_FIELD;
					 break;
				 case Sensor.TYPE_ORIENTATION:
					 result |= SensorManager.SENSOR_ORIENTATION
					 | SensorManager.SENSOR_ORIENTATION_RAW;
					 break;
				 }
			 }
			 return result;

		 }
	 }

	 public List getSensorList(int type) {
		 // cache the returned lists the first time
		 List list = new ArrayList();
		 synchronized (mSensors) {
			 if (type == Sensor.TYPE_ALL) {
				 list.addAll(mSensors);
			 } else {
				 for (android.hardware.Sensor s : mSensors) {
					 if (s.getType() == type) {
						 list.add(s);
					 }
				 }
			 }
		 }
		 return list;
	 }

	 public android.hardware.Sensor getDefaultSensor(int type) {
		 // TODO: need to be smarter, for now, just return the 1st sensor
		 List l = getSensorList(type);
		 return l.isEmpty() ? null : l.get(0);
	 }

	 @Deprecated
	 public boolean registerListener(android.hardware.SensorListener listener, int sensors) {
		 return registerListener(listener, sensors, SENSOR_DELAY_NORMAL);
	 }

	 @Deprecated
	 public boolean registerListener(android.hardware.SensorListener listener, int sensors,
			 int rate) {
		 if (listener == null) {
			 return false;
		 }
		 boolean result = false;
		 result = registerLegacyListener(SENSOR_ACCELEROMETER,
				 Sensor.TYPE_ACCELEROMETER, listener, sensors, rate) || result;
		 result = registerLegacyListener(SENSOR_MAGNETIC_FIELD,
				 Sensor.TYPE_MAGNETIC_FIELD, listener, sensors, rate) || result;
		 result = registerLegacyListener(SENSOR_ORIENTATION_RAW,
				 Sensor.TYPE_ORIENTATION, listener, sensors, rate) || result;
		 result = registerLegacyListener(SENSOR_ORIENTATION,
				 Sensor.TYPE_ORIENTATION, listener, sensors, rate) || result;
		 result = registerLegacyListener(SENSOR_TEMPERATURE,
				 Sensor.TYPE_TEMPERATURE, listener, sensors, rate) || result;
		 return result;
	 }

	 @SuppressWarnings("deprecation")
	 private boolean registerLegacyListener(int legacyType, int type,
			 android.hardware.SensorListener listener, int sensors, int rate) {
		 return true;
	 }

	 @Deprecated
	 public void unregisterListener(android.hardware.SensorListener listener, int sensors) {
		 unregisterLegacyListener(SENSOR_ACCELEROMETER,
				 Sensor.TYPE_ACCELEROMETER, listener, sensors);
		 unregisterLegacyListener(SENSOR_MAGNETIC_FIELD,
				 Sensor.TYPE_MAGNETIC_FIELD, listener, sensors);
		 unregisterLegacyListener(SENSOR_ORIENTATION_RAW,
				 Sensor.TYPE_ORIENTATION, listener, sensors);
		 unregisterLegacyListener(SENSOR_ORIENTATION, Sensor.TYPE_ORIENTATION,
				 listener, sensors);
		 unregisterLegacyListener(SENSOR_TEMPERATURE, Sensor.TYPE_TEMPERATURE,
				 listener, sensors);
	 }

	 @SuppressWarnings("deprecation")
	 private void unregisterLegacyListener(int legacyType, int type,
			 android.hardware.SensorListener listener, int sensors) {

	 }

	 @Deprecated
	 public void unregisterListener(android.hardware.SensorListener listener) {
		 unregisterListener(listener, SENSOR_ALL | SENSOR_ORIENTATION_RAW);
	 }


	 public void unregisterListener(android.hardware.SensorEventListener listener, android.hardware.Sensor sensor) {
		 unregisterListener((Object) listener, sensor);
	 }

	 public void unregisterListener(android.hardware.SensorEventListener listener) {
		 unregisterListener((Object) listener);
	 }

	 public boolean registerListener(android.hardware.SensorEventListener listener,
			 android.hardware.Sensor sensor, int rate) {
		 return registerListener(listener, sensor, rate, null);
	 }

	 public boolean registerListener(android.hardware.SensorEventListener listener,
			 android.hardware.Sensor sensor, int rate, Handler handler) {
		 if (listener == null || sensor == null) {
			 return false;
		 }

		 boolean result = true;
		 int delay = -1;
		 switch (rate) {
		 case SENSOR_DELAY_FASTEST:
			 delay = 0;
			 break;
		 case SENSOR_DELAY_GAME:
			 delay = 20000;
			 break;
		 case SENSOR_DELAY_UI:
			 delay = 60000;
			 break;
		 case SENSOR_DELAY_NORMAL:
			 delay = 200000;
			 break;
		 default:
			 delay = rate;
			 break;
		 }

		 synchronized (mListeners) {
			 for (FullListener fl : mListeners) {
				 if (fl.sensorEventListener == listener && fl.sensor == sensor) {
					 return true;
				 }
			 }
			 FullListener fl = new FullListener();
			 fl.handler = handler;
			 fl.rate = delay;
			 fl.sensorEventListener = listener;
			 fl.sensor = sensor;
			 mListeners.add(fl);
			 result = true;
		 }
		 return result;
	 }

	 private void unregisterListener(Object listener, android.hardware.Sensor sensor) {
		 if (listener == null || sensor == null) {
			 return;
		 }

		 synchronized (mListeners) {
			 final int size = mListeners.size();
			 for (int i = 0; i < size; i++) {
				 FullListener fl = mListeners.get(i);
				 if (fl.sensorEventListener == listener && fl.sensor == sensor) {
					 mListeners.remove(i);
					 break;
				 }
			 }
		 }
	 }

	 private void unregisterListener(Object listener) {
		 if (listener == null) {
			 return;
		 }

		 synchronized (mListeners) {
			 int size = mListeners.size();
			 for (int i = 0; i < size; i++) {
				 FullListener fl = mListeners.get(i);
				 if (fl.sensorEventListener == listener) {
					 mListeners.remove(i);
					 size = mListeners.size();
					 i = 0;
				 }
			 }
			 if(mListeners.isEmpty()) {
				 sensorEventService.stop();
				 sSensorModuleInitialized = false;
			 }
		 }
	 }

	 public static boolean getRotationMatrix(float[] R, float[] I,
			 float[] gravity, float[] geomagnetic) {
		 // TODO: move this to native code for efficiency
		 float Ax = gravity[0];
		 float Ay = gravity[1];
		 float Az = gravity[2];
		 final float Ex = geomagnetic[0];
		 final float Ey = geomagnetic[1];
		 final float Ez = geomagnetic[2];
		 float Hx = Ey * Az - Ez * Ay;
		 float Hy = Ez * Ax - Ex * Az;
		 float Hz = Ex * Ay - Ey * Ax;
		 final float normH = (float) Math.sqrt(Hx * Hx + Hy * Hy + Hz * Hz);
		 if (normH < 0.1f) {
			 // device is close to free fall (or in space?), or close to
			 // magnetic north pole. Typical values are > 100.
			 return false;
		 }
		 final float invH = 1.0f / normH;
		 Hx *= invH;
		 Hy *= invH;
		 Hz *= invH;
		 final float invA = 1.0f / (float) Math
				 .sqrt(Ax * Ax + Ay * Ay + Az * Az);
		 Ax *= invA;
		 Ay *= invA;
		 Az *= invA;
		 final float Mx = Ay * Hz - Az * Hy;
		 final float My = Az * Hx - Ax * Hz;
		 final float Mz = Ax * Hy - Ay * Hx;
		 if (R != null) {
			 if (R.length == 9) {
				 R[0] = Hx;
				 R[1] = Hy;
				 R[2] = Hz;
				 R[3] = Mx;
				 R[4] = My;
				 R[5] = Mz;
				 R[6] = Ax;
				 R[7] = Ay;
				 R[8] = Az;
			 } else if (R.length == 16) {
				 R[0] = Hx;
				 R[1] = Hy;
				 R[2] = Hz;
				 R[3] = 0;
				 R[4] = Mx;
				 R[5] = My;
				 R[6] = Mz;
				 R[7] = 0;
				 R[8] = Ax;
				 R[9] = Ay;
				 R[10] = Az;
				 R[11] = 0;
				 R[12] = 0;
				 R[13] = 0;
				 R[14] = 0;
				 R[15] = 1;
			 }
		 }
		 if (I != null) {
			 // compute the inclination matrix by projecting the geomagnetic
			 // vector onto the Z (gravity) and X (horizontal component
					 // of geomagnetic vector) axes.
					 final float invE = 1.0f / (float) Math.sqrt(Ex * Ex + Ey * Ey + Ez
							 * Ez);
			 final float c = (Ex * Mx + Ey * My + Ez * Mz) * invE;
			 final float s = (Ex * Ax + Ey * Ay + Ez * Az) * invE;
			 if (I.length == 9) {
				 I[0] = 1;
				 I[1] = 0;
				 I[2] = 0;
				 I[3] = 0;
				 I[4] = c;
				 I[5] = s;
				 I[6] = 0;
				 I[7] = -s;
				 I[8] = c;
			 } else if (I.length == 16) {
				 I[0] = 1;
				 I[1] = 0;
				 I[2] = 0;
				 I[4] = 0;
				 I[5] = c;
				 I[6] = s;
				 I[8] = 0;
				 I[9] = -s;
				 I[10] = c;
				 I[3] = I[7] = I[11] = I[12] = I[13] = I[14] = 0;
				 I[15] = 1;
			 }
		 }
		 return true;
	 }

	 public static float getInclination(float[] I) {
		 if (I.length == 9) {
			 return (float) Math.atan2(I[5], I[4]);
		 } else {
			 return (float) Math.atan2(I[6], I[5]);
		 }
	 }

	 public static boolean remapCoordinateSystem(float[] inR, int X, int Y,
			 float[] outR) {
		 if (inR == outR) {
			 final float[] temp = mTempMatrix;
			 synchronized (temp) {
				 // we don't expect to have a lot of contention
				 if (remapCoordinateSystemImpl(inR, X, Y, temp)) {
					 final int size = outR.length;
					 for (int i = 0; i < size; i++) {
						 outR[i] = temp[i];
					 }
					 return true;
				 }
			 }
		 }
		 return remapCoordinateSystemImpl(inR, X, Y, outR);
	 }

	 private static boolean remapCoordinateSystemImpl(float[] inR, int X, int Y,
			 float[] outR) {


		 final int length = outR.length;
		 if (inR.length != length) {
			 return false; // invalid parameter
		 }
		 if ((X & 0x7C) != 0 || (Y & 0x7C) != 0) {
			 return false; // invalid parameter
		 }
		 if (((X & 0x3) == 0) || ((Y & 0x3) == 0)) {
			 return false; // no axis specified
		 }
		 if ((X & 0x3) == (Y & 0x3)) {
			 return false; // same axis specified
		 }
		 // Z is "the other" axis, its sign is either +/- sign(X)*sign(Y)
		 // this can be calculated by exclusive-or'ing X and Y; except for
		 // the sign inversion (+/-) which is calculated below.
		 int Z = X ^ Y;

		 // extract the axis (remove the sign), offset in the range 0 to 2.
		 final int x = (X & 0x3) - 1;
		 final int y = (Y & 0x3) - 1;
		 final int z = (Z & 0x3) - 1;

		 // compute the sign of Z (whether it needs to be inverted)
		 final int axis_y = (z + 1) % 3;
		 final int axis_z = (z + 2) % 3;
		 if (((x ^ axis_y) | (y ^ axis_z)) != 0) {
			 Z ^= 0x80;
		 }

		 final boolean sx = (X >= 0x80);
		 final boolean sy = (Y >= 0x80);
		 final boolean sz = (Z >= 0x80);

		 // Perform R * r, in avoiding actual muls and adds.
		 final int rowLength = ((length == 16) ? 4 : 3);
		 for (int j = 0; j < 3; j++) {
			 final int offset = j * rowLength;
			 for (int i = 0; i < 3; i++) {
				 if (x == i) {
					 outR[offset + i] = sx ? -inR[offset + 0] : inR[offset + 0];
				 }
				 if (y == i) {
					 outR[offset + i] = sy ? -inR[offset + 1] : inR[offset + 1];
				 }
				 if (z == i) {
					 outR[offset + i] = sz ? -inR[offset + 2] : inR[offset + 2];
				 }
			 }
		 }
		 if (length == 16) {
			 outR[3] = outR[7] = outR[11] = outR[12] = outR[13] = outR[14] = 0;
			 outR[15] = 1;
		 }
		 return true;
	 }

	 public static float[] getOrientation(float[] R, float values[]) {
		 /*
		  * 4x4 (length=16) case: / R[ 0] R[ 1] R[ 2] 0 \ | R[ 4] R[ 5] R[ 6] 0 |
		  * | R[ 8] R[ 9] R[10] 0 | \ 0 0 0 1 /
		  * 
		  * 3x3 (length=9) case: / R[ 0] R[ 1] R[ 2] \ | R[ 3] R[ 4] R[ 5] | \ R[
		  * 6] R[ 7] R[ 8] /
		  */
		 if (R.length == 9) {
			 values[0] = (float) Math.atan2(R[1], R[4]);
			 values[1] = (float) Math.asin(-R[7]);
			 values[2] = (float) Math.atan2(-R[6], R[8]);
		 } else {
			 values[0] = (float) Math.atan2(R[1], R[5]);
			 values[1] = (float) Math.asin(-R[9]);
			 values[2] = (float) Math.atan2(-R[8], R[10]);
		 }
		 return values;
	 }

	 public static float getAltitude(float p0, float p) {
		 final float coef = 1.0f / 5.255f;
		 return 44330.0f * (1.0f - (float) Math.pow(p / p0, coef));
	 }

	 class LmsFilter {

		 private static final int SENSORS_RATE_MS = 20;
		 private static final int COUNT = 12;
		 private static final float PREDICTION_RATIO = 1.0f / 3.0f;
		 private static final float PREDICTION_TIME = (SENSORS_RATE_MS * COUNT / 1000.0f)
				 * PREDICTION_RATIO;
		 private float mV[] = new float[COUNT * 2];
		 private float mT[] = new float[COUNT * 2];
		 private int mIndex;

		 public LmsFilter() {
			 mIndex = COUNT;
		 }

		 public float filter(long time, float in) {
			 float v = in;
			 final float ns = 1.0f / 1000000000.0f;
			 final float t = time * ns;
			 float v1 = mV[mIndex];
			 if ((v - v1) > 180) {
				 v -= 360;
			 } else if ((v1 - v) > 180) {
				 v += 360;
			 }
			 /*
			  * Manage the circular buffer, we write the data twice spaced by
			  * COUNT values, so that we don't have to copy the array when it's
			  * full
			  */
			 mIndex++;
			 if (mIndex >= COUNT * 2) {
				 mIndex = COUNT;
			 }
			 mV[mIndex] = v;
			 mT[mIndex] = t;
			 mV[mIndex - COUNT] = v;
			 mT[mIndex - COUNT] = t;

			 float A, B, C, D, E;
			 float a, b;
			 int i;

			 A = B = C = D = E = 0;
			 for (i = 0; i < COUNT - 1; i++) {
				 final int j = mIndex - 1 - i;
				 final float Z = mV[j];
				 final float T = 0.5f * (mT[j] + mT[j + 1]) - t;
				 float dT = mT[j] - mT[j + 1];
				 dT *= dT;
				 A += Z * dT;
				 B += T * (T * dT);
				 C += (T * dT);
				 D += Z * (T * dT);
				 E += dT;
			 }
			 b = (A * B + C * D) / (E * B + C * C);
			 a = (E * b - A) / C;
			 float f = b + PREDICTION_TIME * a;

			 // Normalize
			 f *= (1.0f / 360.0f);
			 if (((f >= 0) ? f : -f) >= 0.5f) {
				 f = f - (float) Math.ceil(f + 0.5f) + 1.0f;
			 }
			 if (f < 0) {
				 f += 1.0f;
			 }
			 f *= 360.0f;
			 return f;
		 }
	 }

	 public static void getAngleChange(float[] angleChange, float[] R,
			 float[] prevR) {
		 float rd1 = 0, rd4 = 0, rd6 = 0, rd7 = 0, rd8 = 0;
		 float ri0 = 0, ri1 = 0, ri2 = 0, ri3 = 0, ri4 = 0, ri5 = 0, ri6 = 0, ri7 = 0, ri8 = 0;
		 float pri0 = 0, pri1 = 0, pri2 = 0, pri3 = 0, pri4 = 0, pri5 = 0, pri6 = 0, pri7 = 0, pri8 = 0;
		 int i, j, k;

		 if (R.length == 9) {
			 ri0 = R[0];
			 ri1 = R[1];
			 ri2 = R[2];
			 ri3 = R[3];
			 ri4 = R[4];
			 ri5 = R[5];
			 ri6 = R[6];
			 ri7 = R[7];
			 ri8 = R[8];
		 } else if (R.length == 16) {
			 ri0 = R[0];
			 ri1 = R[1];
			 ri2 = R[2];
			 ri3 = R[4];
			 ri4 = R[5];
			 ri5 = R[6];
			 ri6 = R[8];
			 ri7 = R[9];
			 ri8 = R[10];
		 }

		 if (prevR.length == 9) {
			 pri0 = prevR[0];
			 pri1 = prevR[1];
			 pri2 = prevR[2];
			 pri3 = prevR[3];
			 pri4 = prevR[4];
			 pri5 = prevR[5];
			 pri6 = prevR[6];
			 pri7 = prevR[7];
			 pri8 = prevR[8];
		 } else if (prevR.length == 16) {
			 pri0 = prevR[0];
			 pri1 = prevR[1];
			 pri2 = prevR[2];
			 pri3 = prevR[4];
			 pri4 = prevR[5];
			 pri5 = prevR[6];
			 pri6 = prevR[8];
			 pri7 = prevR[9];
			 pri8 = prevR[10];
		 }

		 // calculate the parts of the rotation difference matrix we need
		 // rd[i][j] = pri[0][i] * ri[0][j] + pri[1][i] * ri[1][j] + pri[2][i] *
		 // ri[2][j];

		 rd1 = pri0 * ri1 + pri3 * ri4 + pri6 * ri7; // rd[0][1]
				 rd4 = pri1 * ri1 + pri4 * ri4 + pri7 * ri7; // rd[1][1]
						 rd6 = pri2 * ri0 + pri5 * ri3 + pri8 * ri6; // rd[2][0]
						 rd7 = pri2 * ri1 + pri5 * ri4 + pri8 * ri7; // rd[2][1]
						 rd8 = pri2 * ri2 + pri5 * ri5 + pri8 * ri8; // rd[2][2]

						 angleChange[0] = (float) Math.atan2(rd1, rd4);
						 angleChange[1] = (float) Math.asin(-rd7);
						 angleChange[2] = (float) Math.atan2(-rd6, rd8);

	 }

	 public static void getRotationMatrixFromVector(float[] R,
			 float[] rotationVector) {

		 float q0;
		 float q1 = rotationVector[0];
		 float q2 = rotationVector[1];
		 float q3 = rotationVector[2];

		 if (rotationVector.length == 4) {
			 q0 = rotationVector[3];
		 } else {
			 q0 = 1 - q1 * q1 - q2 * q2 - q3 * q3;
			 q0 = (q0 > 0) ? (float) Math.sqrt(q0) : 0;
		 }

		 float sq_q1 = 2 * q1 * q1;
		 float sq_q2 = 2 * q2 * q2;
		 float sq_q3 = 2 * q3 * q3;
		 float q1_q2 = 2 * q1 * q2;
		 float q3_q0 = 2 * q3 * q0;
		 float q1_q3 = 2 * q1 * q3;
		 float q2_q0 = 2 * q2 * q0;
		 float q2_q3 = 2 * q2 * q3;
		 float q1_q0 = 2 * q1 * q0;

		 if (R.length == 9) {
			 R[0] = 1 - sq_q2 - sq_q3;
			 R[1] = q1_q2 - q3_q0;
			 R[2] = q1_q3 + q2_q0;

			 R[3] = q1_q2 + q3_q0;
			 R[4] = 1 - sq_q1 - sq_q3;
			 R[5] = q2_q3 - q1_q0;

			 R[6] = q1_q3 - q2_q0;
			 R[7] = q2_q3 + q1_q0;
			 R[8] = 1 - sq_q1 - sq_q2;
		 } else if (R.length == 16) {
			 R[0] = 1 - sq_q2 - sq_q3;
			 R[1] = q1_q2 - q3_q0;
			 R[2] = q1_q3 + q2_q0;
			 R[3] = 0.0f;

			 R[4] = q1_q2 + q3_q0;
			 R[5] = 1 - sq_q1 - sq_q3;
			 R[6] = q2_q3 - q1_q0;
			 R[7] = 0.0f;

			 R[8] = q1_q3 - q2_q0;
			 R[9] = q2_q3 + q1_q0;
			 R[10] = 1 - sq_q1 - sq_q2;
			 R[11] = 0.0f;

			 R[12] = R[13] = R[14] = 0.0f;
			 R[15] = 1.0f;
		 }
	 }

	 public static void getQuaternionFromVector(float[] Q, float[] rv) {
		 if (rv.length == 4) {
			 Q[0] = rv[3];
		 } else {
			 Q[0] = 1 - rv[0] * rv[0] - rv[1] * rv[1] - rv[2] * rv[2];
			 Q[0] = (Q[0] > 0) ? (float) Math.sqrt(Q[0]) : 0;
		 }
		 Q[1] = rv[0];
		 Q[2] = rv[1];
		 Q[3] = rv[2];
	 }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy