/**
Copyright 2015 Tim Engler, Rareventure LLC
This file is part of Tiny Travel Tracker.
Tiny Travel Tracker is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Tiny Travel Tracker is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Tiny Travel Tracker. If not, see <http://www.gnu.org/licenses/>.
*/
package com.rareventure.android;
import com.rareventure.android.AndroidPreferenceSet.AndroidPreferences;
/**
* Determines the direction of the compass by taking a rolling average.
*/
public class CompassDirectionCalculator {
private long lastTime;
private Preferences prefs = new Preferences();
private float currAvgDirection;
private long currAvgDirectionStartTimeMs;
/**
* The last average direction the compass was facing over the minimum period
* or longer
*/
public float lastAvgDirection;
/**
* The time the compass started facing the last avg direction
*/
public long lastAvgDirectionStartTimeMs;
/**
* The time the compass stopped facing the last avg direction
*/
public long lastAvgDirectionEndTimeMs;
/**
*
* @param time time of reading
* @param direction direction in degrees from 0 to 360
* @return true if there is a significant change in direction (see lastDirection* for values)
*/
public boolean processCompass(long time, float direction)
{
if(lastTime == 0)
{
lastTime = time-1;
currAvgDirectionStartTimeMs = time-1;
currAvgDirection = direction;
return false;
}
//if we can break off to another direction
if(time - currAvgDirectionStartTimeMs >= prefs.minDirectionTimeMs)
{
//if we've changed direction enough that we want to break it off now
if(Math.abs(direction - adjustDirectionForCompare(currAvgDirection, direction))
> prefs.minDegreesForChange)
{
lastAvgDirection = currAvgDirection;
lastAvgDirectionStartTimeMs = currAvgDirectionStartTimeMs;
lastAvgDirectionEndTimeMs = lastTime;
currAvgDirectionStartTimeMs = time;
currAvgDirection = direction;
return true;
}
}
//make curr direction the average of all the directions over the specified time period
currAvgDirection = (currAvgDirection * (lastTime - currAvgDirectionStartTimeMs) +
adjustDirectionForCompare(direction, currAvgDirection) * (time - lastTime))
/ (time - currAvgDirectionStartTimeMs);
currAvgDirection = adjustDirection(currAvgDirection);
lastTime = time;
return false;
}
/**
* Standardizes a compass direction from 0 to 360 degrees
*/
private float adjustDirection(float dir) {
if(dir < 0)
return dir + 360;
if(dir >= 360)
return dir - 360;
return dir;
}
/**
* Adjusts a compass direction for comparision with another direction.
* Makes sure the compass values are at most -/+ 180 degrees of each other.
* So, for example, if the first is 359 degrees and the second is 1 degree, it will return
* the first one adjusted to -1 degrees.
*
* @param direction direction to modify
* @param directionToCompare comparision direction
* @return direction, modified to be close to directionToCompare in absolute terms
*/
private float adjustDirectionForCompare(float direction, float directionToCompare) {
if(direction - directionToCompare > 180)
direction -= 360;
else if(direction - directionToCompare < - 180)
direction += 360;
return direction;
}
public static class Preferences implements AndroidPreferences
{
/**
* The minimum time period a change in direction has to be before it is registered
*/
public long minDirectionTimeMs = 30*1000;
/**
* The minimum number of degrees that the current direction is different from the previous
* one to record a change in the database
*/
public float minDegreesForChange = 10;
/**
* Amount to adjust the rolling average compass value per ms
*/
public float compassAdjustmentPerMs = 1f / (15 * 1000);
}
}