package actions;
import geo.GeoCalcer;
import gl.GLCamera;
import system.EventManager;
import util.Log;
import worldData.World;
import android.location.Location;
/**
* This action is the basic action for virtual camera movement in relation to
* the physical device movement. The GPS input is used to calculate the virtual
* position. If the distance to the center of the virtual world gets to big, the
* virtual zero position is reseted and the virtual positions are recalculated
*
* <br>
* latutude is north(+)/south(-)<br>
* longitude is east(+)/west(-)<br>
*
* TODO combine this with the moveCamera action? good idea or not?
*
* @author Spobo
*
*/
public class ActionCalcRelativePos extends Action {
/**
* On default this is false, because the altitude values received via GPS
* are very inaccurate
*
* set this to true if your scenario need to take altitude values into
* account
*/
public static boolean USE_ALTITUDE_VALUES = false;
/**
* set this to false if you want to position objects at the real 0 altitude,
* because otherwise if you set altitude to 0 the current device altitude
* will be used
*/
public static final boolean USE_DEVICE_ALTI_FOR_ZERO = true;
private static final double MAX_METER_DISTANCE = 1000; // 500 meter
private static final String LOG_TAG = "ActionCalcRelativePos";
private static final boolean LOG_SHOW_POSITION = false;
/**
* this could be replaces by the
* {@link EventManager#getZeroPositionLocationObject()} values. Should store
* the same information. where is the better place to store the data TODO
*/
private double nullLongitude;
private double nullLatitude;
private double nullAltitude;
private World myWorld;
private GLCamera myCamera;
private GeoCalcer myGeoCalcer;
public ActionCalcRelativePos(World world, GLCamera camera) {
myWorld = world;
myCamera = camera;
}
@Override
public boolean onLocationChanged(Location location) {
if (nullLatitude == 0 || nullLongitude == 0) {
/*
* if the nullLat or nullLong are 0 this method was probably never
* called before (TODO problem when living in greenwhich e.g.?)
*/
resetWorldZeroPositions(location);
} else {
/*
* the following calculations were extracted from
* GeoObj.calcVirtualPosition() for further explanation how they
* work read the javadoc there. the two calculations were extracted
* to increase performance because this method will be called every
* time a new GPS-position arrives
*/
final double latitudeDistInMeters = (location.getLatitude() - nullLatitude) * 111133.3333;
final double longitudeDistInMeters = (location.getLongitude() - nullLongitude)
* 111319.4917 * Math.cos(nullLatitude * 0.0174532925);
if (LOG_SHOW_POSITION) {
Log.v(LOG_TAG, "latutude dist (north(+)/south(-))="
+ latitudeDistInMeters);
Log.v(LOG_TAG, "longitude dist (east(+)/west(-))="
+ longitudeDistInMeters);
}
if (worldShouldBeRecalced(latitudeDistInMeters,
longitudeDistInMeters)) {
resetWorldZeroPositions(location);
} else {
if (USE_ALTITUDE_VALUES) {
/*
* if the altitude values should be used calculate the
* correct height
*/
final double relativeHeight = location.getAltitude()
- nullAltitude;
myCamera.setNewPosition((float) longitudeDistInMeters,
(float) latitudeDistInMeters,
(float) relativeHeight);
} else {
// else dont change the z value
myCamera.setNewPosition((float) longitudeDistInMeters,
(float) latitudeDistInMeters);
}
}
}
return true;
}
private void resetCameraToNullPosition() {
myCamera.resetPosition(false);
}
private boolean worldShouldBeRecalced(double latDistMet, double longDistMet) {
if (Math.abs(latDistMet) > MAX_METER_DISTANCE)
return true;
if (Math.abs(longDistMet) > MAX_METER_DISTANCE)
return true;
return false;
}
public void resetWorldZeroPositions(Location location) {
Log.d(LOG_TAG, "Reseting virtual world positions");
setNewNullValues(location);
resetCameraToNullPosition();
calcNewWorldPositions();
}
private void setNewNullValues(Location location) {
nullLatitude = location.getLatitude();
nullLongitude = location.getLongitude();
nullAltitude = location.getAltitude();
EventManager.getInstance().setZeroLocation(location);
}
private void calcNewWorldPositions() {
if (myGeoCalcer == null)
myGeoCalcer = new GeoCalcer();
myGeoCalcer.setNullPos(nullLatitude, nullLongitude, nullAltitude);
myWorld.accept(myGeoCalcer);
}
}