How can I calculate the bearing/ heading between two GeoPoints ? (lat/lng)) - flutter

Here is the logic, I get some latitude and longitude points from the server, I them compare the last received point with the points I receive next and use a function to get the bearing/heading between these points,
In order to do so i need to have 4 double variables of those points, bearingLat and bearingLon will hold the last point while the driverLat and driverLon hold the newer points. now i use the method Geolocator.bearingBetween( driverLat!, driverLon!, bearingLat, bearingLon); to get the bearing, the problem is driverLat will equal bearingLat while driverlon will equal bearing lon , when I print out it gives a result like this heading 27.77351058, 85.36021874, 27.77351058, 85.36021874,
My objective is to get
bearingBetween(
double startLatitude,
double startLongitude,
double endLatitude,
double endLongitude,
)
the class
class UpdateDrivers {
MapController osmController;
bool removeDriverIcon;
String? removeDriverKey;
double? driverLon;
String? driverKey;
double? driverLat;
double bearingLat = 0;
double bearingLon = 0;
static const double twoPi = 2 * pi;
//double twoPi = 2 * pi;
UpdateDrivers({
required this.osmController,
required this.removeDriverIcon,
this.removeDriverKey,
});
void updateAvailableDriversOnMap() async {
if (removeDriverIcon) {
//removes the car when the driver goes offline
await osmController.setStaticPosition([], removeDriverKey!);
removeDriverIcon = false;
removeDriverKey = null;
} else {
if (GeoFireAssistant.nearByAvailableDriversList.length > 0)
for (NearByAvailableDrivers driver
in GeoFireAssistant.nearByAvailableDriversList) {
driverKey = driver.key!;
driverLat = driver.latitude!;
driverLon = driver.longitude!;
double z = Geolocator.bearingBetween(
driverLat!, driverLon!, bearingLat, bearingLon);
print("heading $z");
bearingLat = driverLat!;
bearingLon = driverLon!;
if (z.isNegative) {
z = (twoPi + z);
}
print("heading " +
driverLat.toString() +
", " +
driverLon.toString() +
", " +
bearingLat.toString() +
", " +
bearingLon.toString() +
", ");
}
}
}
}
Here is the log to show I am actually receiving different GeoPoint just not able to handle the function,
below in the 3rd line it should be heading 27.77351071, 85.36021885, 27.77351097, 85.36021822
I/flutter (13573): heading 27.77351097, 85.36021822, 27.77351097, 85.36021822,
I/flutter (13573): heading 62.148877298990115
I/flutter (13573): heading 27.77351071, 85.36021885, 27.77351071, 85.36021885,
I/flutter (13573): heading 62.14887839428785
I/flutter (13573): heading 27.7735096, 85.36021835, 27.7735096, 85.36021835,
I/flutter (13573): heading 62.1488777544798
I/flutter (13573): heading 27.77351025, 85.36021869, 27.77351025, 85.36021869,
I/flutter (13573): heading 62.14887819652214
I/flutter (13573): heading 27.77350978, 85.36021783, 27.77350978, 85.36021783,
I/flutter (13573): heading 62.14887680439367
I/flutter (13573): heading 27.7735112, 85.36021874, 27.7735112, 85.36021874,
Edit- My function is correct, I tried to manually put in Geopoint and calculate the bearing the result is correct, my only issue is bearinglat and bearinglon not taking the last value of driverlat and driverlon
I think its how I instantiated double bearingLat = 0; double bearingLon = 0; in the constructor?
Iam calling it from another class in this way
case Geofire.onKeyMoved:
NearByAvailableDrivers nearByAvailableDrivers =
NearByAvailableDrivers(
map['key'], map['latitude'], map['longitude']);
GeoFireAssistant.updateDriverNearByLocation(
nearByAvailableDrivers);
UpdateDrivers updateDrivers = UpdateDrivers(
osmController: osmController,
removeDriverIcon: false,
);
updateDrivers.updateAvailableDriversOnMap();
break;

Here it is in Java.
private static double angleFromCoordinate(double lat1, double long1, double lat2,
double long2) {
double dLon = (long2 - long1);
double y = Math.sin(dLon) * Math.cos(lat2);
double x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1)
* Math.cos(lat2) * Math.cos(dLon);
double brng = Math.atan2(y, x);
brng = Math.toDegrees(brng);
brng = (brng + 360) % 360;
brng = 360 - brng; // count degrees counter-clockwise - remove to make clockwise
return brng;

Related

how to find Qibla angle in Flutter Qibla

#Here is my current code to get angle but this is in decimal value I want to get in angle from 1 to 360 degree#
final qiblahDirection = snapshot.data;
var _angle = ((qiblahDirection.qiblah ?? 0) * (pi / 180) * -1
double calculateQiblaDirection(Coordinates coordinates) {
// Equation from "Spherical Trigonometry For the use of colleges and schools" page 50
final longitudeDelta =
radians(makkah.longitude) - radians(coordinates.longitude);
final latitudeRadians = radians(coordinates.latitude);
final term1 = sin(longitudeDelta);
final term2 = cos(latitudeRadians) * tan(radians(makkah.latitude));
final term3 = sin(latitudeRadians) * cos(longitudeDelta);
final angle = atan2(term1, term2 - term3);
return DoubleUtil.unwindAngle(degrees(angle));
}
class DoubleUtil {
static double normalizeWithBound(double value, double max) {
return value - (max * ((value / max).floorToDouble()));
}
static double unwindAngle(double value) {
return normalizeWithBound(value, 360);
}
static double closestAngle(double angle) {
if (angle >= -180 && angle <= 180) {
return angle;
}
return angle - (360 * (angle / 360).roundToDouble());
}
}

Flutter polyline distance with google_maps_flutter plugin

Hi I am using the google_maps_flutter plug in and have gotten a polyline to show up on my map. What I would like to do is calculate the distance of the polyline length. My code is linked here and there is a snippet below. I do not want to use the Directions API. How do I calculate polyline distance and print to console? Thanks for reading.
class ShowMap extends StatefulWidget {
final double lat;
final double lng;
ShowMap({Key key, this.lat, this.lng}) : super(key: key);
#override
_ShowMapState createState() => _ShowMapState();
}
class _ShowMapState extends State<ShowMap> {
// Field
double lat, lng;
BitmapDescriptor policeIcon;
List<Marker> list = List();
List<String> listDocuments = List();
final Set<Polyline> _polyline = {};
GoogleMapController controller;
List<LatLng> latlngSegment1 = List();
List<LatLng> latlngSegment2 = List();
static LatLng _lat1 = LatLng(45.19, -121.59);
static LatLng _lat2 = LatLng(45.30, -122.20);
static LatLng _lat3 = LatLng(45.11, -122.61);
static LatLng _lat4 = LatLng(45.42, -122.62);
static LatLng _lat5 = LatLng(45.34, -122.32);
static LatLng _lat6 = LatLng(45.21, -122.2);
bool _myLocationButtonEnabled = true;
bool _myLocationEnabled = true;
// Method
#override
void initState() {
super.initState();
// findLatLng();
readDataFromFirebase();
setState(() {
lat = widget.lat;
lng = widget.lng;
latlngSegment1.add(_lat1);
latlngSegment1.add(_lat2);
latlngSegment1.add(_lat3);
latlngSegment1.add(_lat4);
//line segment 2
latlngSegment2.add(_lat4);
latlngSegment2.add(_lat5);
latlngSegment2.add(_lat6);
latlngSegment2.add(_lat1);
});
}
Let us say that you want to calculate the distance of polyline created by the points in latlngSegment1.
For that you need to calculate the distance between each consecutive LatLng points in latlngSegment1.
I would do it with something like this.
double calculateDistane(List<LatLng> polyline) {
double totalDistance = 0;
for (int i = 0; i < polyline.length; i++) {
if (i < polyline.length - 1) { // skip the last index
totalDistance += getStraightLineDistance(
polyline[i + 1].latitude,
polyline[i + 1].longitude,
polyline[i].latitude,
polyline[i].longitude);
}
}
return totalDistance;
}
double getStraightLineDistance(lat1, lon1, lat2, lon2) {
var R = 6371; // Radius of the earth in km
var dLat = deg2rad(lat2 - lat1);
var dLon = deg2rad(lon2 - lon1);
var a = math.sin(dLat / 2) * math.sin(dLat / 2) +
math.cos(deg2rad(lat1)) *
math.cos(deg2rad(lat2)) *
math.sin(dLon / 2) *
math.sin(dLon / 2);
var c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a));
var d = R * c; // Distance in km
return d * 1000; //in m
}
dynamic deg2rad(deg) {
return deg * (math.pi / 180);
}
Note: The getStraightLineDistance() function gives the straight line distance between two latlng points, which might not be the way someone reaches from point A to B.

How to return distances below 10km way flutter

Managed to sort my snapshots by those nearest to the user's location, but am having trouble showing only those that are within a returned distance of 10(km). I tried writing if statements above return totalDistance in the distance function, but no luck. Any help would be appreciated!
double calculateDistance(lat1, lon1, lat2, lon2){
var p = 0.017453292519943295;
var c = cos;
var a = 0.5 - c((lat2 - lat1) * p)/2 +
c(lat1 * p) * c(lat2 * p) *
(1 - c((lon2 - lon1) * p))/2;
return 12742 * asin(sqrt(a));
}
double distance(Position position, DocumentSnapshot snapshot){
final double myPositionLat = position.latitude;
final double myPositionLong = position.longitude;
final double lat = snapshot.data['latitude'];
final double long = snapshot.data['longitude'];
double totalDistance = calculateDistance(myPositionLat, myPositionLong, lat, long);
return totalDistance;
}
#override
void initState() {
super.initState();
subscription = collectionReference.snapshots().listen((data) async {
final location = await getLocation();
print('user location = $location');
final documents = data.documents;
documents.sort((a, b) {
final distanceA = distance(location, a);
final distanceB = distance(location, b);
return distanceA.compareTo(distanceB);
});
}
Try using where to filter the list. I've never used Dart but I imagine it looks something like this:
final documents = data.documents.where((a) => distance(location, a) < 10);
Maybe tack on .toList(); if you want an actual List and not an Iterable.

How to get radius of a Circle Shape after I scaled it [JavaFX]

I'm trying to get the radius of a Circle Shape after I scaled it. I don't know how to do it. I'm developing a software (with javaFX library) that will let the user add Shapes (Circle, Rectangle, Squares,...)to a Panel, simply "modify" them, save the drawing and load it. I'm managing the saving/loading stuff by cycling through the Nodes the user added (there's a button to create Circle, Rectangle, ... and add it to the Panel), taking the properties I need to load them (centerX, centerY, scaleX, scaleY, ...) and, when button "save" pressed, to save them in a txt file. (stil working on loading, but my thought was to read the previous txt file and cycle it to re-create Shapes on panel in the same position, scale, rotation.)
Here's the code I wrote this is the portion of code that create circle:
public Circle createCircle(double x, double y, double r, Color color) {
Circle circle = new Circle(x, y, r, color);
circle.setCursor(Cursor.HAND);
circle.setOnMousePressed((t) -> {
orgSceneX = t.getSceneX();
orgSceneY = t.getSceneY();
Circle c = (Circle) (t.getSource());
c.toFront();
});
circle.setOnMouseDragged((t) -> {
double offsetX = t.getSceneX() - orgSceneX;
double offsetY = t.getSceneY() - orgSceneY;
Circle c = (Circle) (t.getSource());
c.setCenterX(c.getCenterX() + offsetX);
c.setCenterY(c.getCenterY() + offsetY);
orgSceneX = t.getSceneX();
orgSceneY = t.getSceneY();
});
return circle;
}
Here's the code i use to scale it:
public void addMouseScrolling(Node node) {
node.setOnScroll((ScrollEvent event) -> {
// Adjust the zoom factor as per your requirement
double zoomFactor = 1.05;
double deltaY = event.getDeltaY();
if (deltaY < 0){
zoomFactor = 2.0 - zoomFactor;
}
node.setScaleX(node.getScaleX() * zoomFactor);
node.setScaleY(node.getScaleY() * zoomFactor);
});
}
And this is the code of the save button:
Button btn2 = new Button("Save");
btn2.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent event) {
int i=0;
for (Node node: root.getChildren()) i++;
String stringa_salvataggio[] = new String[i];
String stringa="";
i=0;
String scal_X_s, scal_Y_s, Lyt_X_s, Lyt_Y_s, width_s, height_s;
for (Node node: root.getChildren()){
String stringa_nodo = node.toString();
Double scal_X = node.getScaleX();
scal_X_s = Double.toString(scal_X);
Double scal_Y = node.getScaleY();
scal_Y_s = Double.toString(scal_X);
Double Lyt_X = node.getLayoutX();
Lyt_X_s = Double.toString(scal_X);
Double Lyt_Y = node.getLayoutY();
Lyt_Y_s = Double.toString(scal_X);
Double width = node.getLayoutBounds().getWidth();
width_s = Double.toString(scal_X);
Double height = node.getLayoutBounds().getHeight();
height_s = Double.toString(scal_X);
stringa = stringa + scal_X_s + scal_Y_s + "\n";
stringa_salvataggio[i] = stringa;
System.out.println("-------");
i++;
System.out.println("Nodo " + i + ":");
System.out.println("scalX:" + scal_X);
System.out.println("scalY:" + scal_Y);
System.out.println("LayoutX:" + Lyt_X);
System.out.println("LayoutY:" + Lyt_Y);
System.out.println("Width:" + width);
System.out.println("Height:" + height);
System.out.println(stringa_nodo);
//save on .txt
}
System.out.println(stringa_salvataggio);
}
});
As I said before, I don't know how to get the radius of Circle to recreate it on loading. Rectangles and squares aren't a problem, I can take all infos I need.
Thanks in advance.

Is it possible to turn gps ground speed and vehical heading to acceleration and yaw angle in NED [duplicate]

I am developing an android application to calculate position based on Sensor's Data
Accelerometer --> Calculate Linear Acceleration
Magnetometer + Accelerometer --> Direction of movement
The initial position will be taken from GPS (Latitude + Longitude).
Now based on Sensor's Readings i need to calculate the new position of the Smartphone:
My Algorithm is following - (But is not calculating Accurate Position): Please help me improve it.
Note: My algorithm Code is in C# (I am sending Sensor Data to Server - Where Data is stored in the Database. I am calculating the position on Server)
All DateTime Objects have been calculated using TimeStamps - From 01-01-1970
var prevLocation = ServerHandler.getLatestPosition(IMEI);
var newLocation = new ReceivedDataDTO()
{
LocationDataDto = new LocationDataDTO(),
UsersDto = new UsersDTO(),
DeviceDto = new DeviceDTO(),
SensorDataDto = new SensorDataDTO()
};
//First Reading
if (prevLocation.Latitude == null)
{
//Save GPS Readings
newLocation.LocationDataDto.DeviceId = ServerHandler.GetDeviceIdByIMEI(IMEI);
newLocation.LocationDataDto.Latitude = Latitude;
newLocation.LocationDataDto.Longitude = Longitude;
newLocation.LocationDataDto.Acceleration = float.Parse(currentAcceleration);
newLocation.LocationDataDto.Direction = float.Parse(currentDirection);
newLocation.LocationDataDto.Speed = (float) 0.0;
newLocation.LocationDataDto.ReadingDateTime = date;
newLocation.DeviceDto.IMEI = IMEI;
// saving to database
ServerHandler.SaveReceivedData(newLocation);
return;
}
//If Previous Position not NULL --> Calculate New Position
**//Algorithm Starts HERE**
var oldLatitude = Double.Parse(prevLocation.Latitude);
var oldLongitude = Double.Parse(prevLocation.Longitude);
var direction = Double.Parse(currentDirection);
Double initialVelocity = prevLocation.Speed;
//Get Current Time to calculate time Travelling - In seconds
var secondsTravelling = date - tripStartTime;
var t = secondsTravelling.TotalSeconds;
//Calculate Distance using physice formula, s= Vi * t + 0.5 * a * t^2
// distanceTravelled = initialVelocity * timeTravelling + 0.5 * currentAcceleration * timeTravelling * timeTravelling;
var distanceTravelled = initialVelocity * t + 0.5 * Double.Parse(currentAcceleration) * t * t;
//Calculate the Final Velocity/ Speed of the device.
// this Final Velocity is the Initil Velocity of the next reading
//Physics Formula: Vf = Vi + a * t
var finalvelocity = initialVelocity + Double.Parse(currentAcceleration) * t;
//Convert from Degree to Radians (For Formula)
oldLatitude = Math.PI * oldLatitude / 180;
oldLongitude = Math.PI * oldLongitude / 180;
direction = Math.PI * direction / 180.0;
//Calculate the New Longitude and Latitude
var newLatitude = Math.Asin(Math.Sin(oldLatitude) * Math.Cos(distanceTravelled / earthRadius) + Math.Cos(oldLatitude) * Math.Sin(distanceTravelled / earthRadius) * Math.Cos(direction));
var newLongitude = oldLongitude + Math.Atan2(Math.Sin(direction) * Math.Sin(distanceTravelled / earthRadius) * Math.Cos(oldLatitude), Math.Cos(distanceTravelled / earthRadius) - Math.Sin(oldLatitude) * Math.Sin(newLatitude));
//Convert From Radian to degree/Decimal
newLatitude = 180 * newLatitude / Math.PI;
newLongitude = 180 * newLongitude / Math.PI;
This is the Result I get --> Phone was not moving. As you can see speed is 27.3263111114502 So there is something wrong in calculating Speed but I don't know what
ANSWER:
I found a solution to calculate position based on Sensor: I have posted an Answer below.
If you need any help, please leave a comment
this is The results compared to GPS (Note: GPS is in Red)
As some of you mentioned you got the equations wrong but that is just a part of the error.
Newton - D'Alembert physics for non relativistic speeds dictates this:
// init values
double ax=0.0,ay=0.0,az=0.0; // acceleration [m/s^2]
double vx=0.0,vy=0.0,vz=0.0; // velocity [m/s]
double x=0.0, y=0.0, z=0.0; // position [m]
// iteration inside some timer (dt [seconds] period) ...
ax,ay,az = accelerometer values
vx+=ax*dt; // update speed via integration of acceleration
vy+=ay*dt;
vz+=az*dt;
x+=vx*dt; // update position via integration of velocity
y+=vy*dt;
z+=vz*dt;
the sensor can rotate so the direction must be applied:
// init values
double gx=0.0,gy=-9.81,gz=0.0; // [edit1] background gravity in map coordinate system [m/s^2]
double ax=0.0,ay=0.0,az=0.0; // acceleration [m/s^2]
double vx=0.0,vy=0.0,vz=0.0; // velocity [m/s]
double x=0.0, y=0.0, z=0.0; // position [m]
double dev[9]; // actual device transform matrix ... local coordinate system
(x,y,z) <- GPS position;
// iteration inside some timer (dt [seconds] period) ...
dev <- compass direction
ax,ay,az = accelerometer values (measured in device space)
(ax,ay,az) = dev*(ax,ay,az); // transform acceleration from device space to global map space without any translation to preserve vector magnitude
ax-=gx; // [edit1] remove background gravity (in map coordinate system)
ay-=gy;
az-=gz;
vx+=ax*dt; // update speed (in map coordinate system)
vy+=ay*dt;
vz+=az*dt;
x+=vx*dt; // update position (in map coordinate system)
y+=vy*dt;
z+=vz*dt;
gx,gy,gz is the global gravity vector (~9.81 m/s^2 on Earth)
in code my global Y axis points up so the gy=-9.81 and the rest are 0.0
measure timings are critical
Accelerometer must be checked as often as possible (second is a very long time). I recommend not to use timer period bigger than 10 ms to preserve accuracy also time to time you should override calculated position with GPS value. Compass direction can be checked less often but with proper filtration
compass is not correct all the time
Compass values should be filtered for some peak values. Sometimes it read bad values and also can be off by electro-magnetic polution or metal enviroment. In that case the direction can be checked by GPS during movement and some corrections can be made. For example chech GPS every minute and compare GPS direction with compass and if it is constantly of by some angle then add it or substract it.
why do simple computations on server ???
Hate on-line waste of traffic. Yes you can log data on server (but still i think file on device will be better) but why to heck limit position functionality by internet connection ??? not to mention the delays ...
[Edit 1] additional notes
Edited the code above a little. The orientation must be as precise as it can be to minimize cumulative errors.
Gyros would be better than compass (or even better use them both). Acceleration should be filtered. Some low pass filtering should be OK. After gravity removal I would limit ax,ay,az to usable values and throw away too small values. If near low speed also do full stop (if it is not a train or motion in vacuum). That should lower the drift but increase other errors so an compromise has to be found between them.
Add calibration on the fly. When filtered acceleration = 9.81 or very close to it then the device is probably stand still (unless its a flying machine). Orientation/direction can be corrected by actual gravity direction.
Acceleration sensors and gyros are not suited for position calculation.
After some seconds the errors become incredible high. (I hardly remember that the double integration is the problem).
Look at this Google tech talk video about sensor fusioning,
he explains in very detail why this is not possible.
After solving the position I calculated using Sensors I would like to post my code here in case anyone needs in future:
Note: This was only checked on Samsung Galaxy S2 phone and only when person was walking with the phone, it has not been tested when moving in car or on bike
This is the result I got when compared when compared with GPS, (Red Line GPS, Blue is Position calculated with Sensor)
The code is not very efficient, but I hope my sharing this code will help someone and point them in the right direction.
I had two seperate classes:
CalculatePosition
CustomSensorService
public class CalculatePosition {
static Double earthRadius = 6378D;
static Double oldLatitude,oldLongitude;
static Boolean IsFirst = true;
static Double sensorLatitude, sensorLongitude;
static Date CollaborationWithGPSTime;
public static float[] results;
public static void calculateNewPosition(Context applicationContext,
Float currentAcceleration, Float currentSpeed,
Float currentDistanceTravelled, Float currentDirection, Float TotalDistance) {
results = new float[3];
if(IsFirst){
CollaborationWithGPSTime = new Date();
Toast.makeText(applicationContext, "First", Toast.LENGTH_LONG).show();
oldLatitude = CustomLocationListener.mLatitude;
oldLongitude = CustomLocationListener.mLongitude;
sensorLatitude = oldLatitude;
sensorLongitude = oldLongitude;
LivePositionActivity.PlotNewPosition(oldLongitude,oldLatitude,currentDistanceTravelled * 1000, currentAcceleration, currentSpeed, currentDirection, "GPSSensor",0.0F,TotalDistance);
IsFirst = false;
return;
}
Date CurrentDateTime = new Date();
if(CurrentDateTime.getTime() - CollaborationWithGPSTime.getTime() > 900000){
//This IF Statement is to Collaborate with GPS position --> For accuracy --> 900,000 == 15 minutes
oldLatitude = CustomLocationListener.mLatitude;
oldLongitude = CustomLocationListener.mLongitude;
LivePositionActivity.PlotNewPosition(oldLongitude,oldLatitude,currentDistanceTravelled * 1000, currentAcceleration, currentSpeed, currentDirection, "GPSSensor", 0.0F, 0.0F);
return;
}
//Convert Variables to Radian for the Formula
oldLatitude = Math.PI * oldLatitude / 180;
oldLongitude = Math.PI * oldLongitude / 180;
currentDirection = (float) (Math.PI * currentDirection / 180.0);
//Formulae to Calculate the NewLAtitude and NewLongtiude
Double newLatitude = Math.asin(Math.sin(oldLatitude) * Math.cos(currentDistanceTravelled / earthRadius) +
Math.cos(oldLatitude) * Math.sin(currentDistanceTravelled / earthRadius) * Math.cos(currentDirection));
Double newLongitude = oldLongitude + Math.atan2(Math.sin(currentDirection) * Math.sin(currentDistanceTravelled / earthRadius)
* Math.cos(oldLatitude), Math.cos(currentDistanceTravelled / earthRadius)
- Math.sin(oldLatitude) * Math.sin(newLatitude));
//Convert Back from radians
newLatitude = 180 * newLatitude / Math.PI;
newLongitude = 180 * newLongitude / Math.PI;
currentDirection = (float) (180 * currentDirection / Math.PI);
//Update old Latitude and Longitude
oldLatitude = newLatitude;
oldLongitude = newLongitude;
sensorLatitude = oldLatitude;
sensorLongitude = oldLongitude;
IsFirst = false;
//Plot Position on Map
LivePositionActivity.PlotNewPosition(newLongitude,newLatitude,currentDistanceTravelled * 1000, currentAcceleration, currentSpeed, currentDirection, "Sensor", results[0],TotalDistance);
}
}
public class CustomSensorService extends Service implements SensorEventListener{
static SensorManager sensorManager;
static Sensor mAccelerometer;
private Sensor mMagnetometer;
private Sensor mLinearAccelertion;
static Context mContext;
private static float[] AccelerometerValue;
private static float[] MagnetometerValue;
public static Float currentAcceleration = 0.0F;
public static Float currentDirection = 0.0F;
public static Float CurrentSpeed = 0.0F;
public static Float CurrentDistanceTravelled = 0.0F;
/*---------------------------------------------*/
float[] prevValues,speed;
float[] currentValues;
float prevTime, currentTime, changeTime,distanceY,distanceX,distanceZ;
float[] currentVelocity;
public static CalculatePosition CalcPosition;
/*-----FILTER VARIABLES-------------------------*-/
*
*
*/
public static Float prevAcceleration = 0.0F;
public static Float prevSpeed = 0.0F;
public static Float prevDistance = 0.0F;
public static Float totalDistance;
TextView tv;
Boolean First,FirstSensor = true;
#Override
public void onCreate(){
super.onCreate();
mContext = getApplicationContext();
CalcPosition = new CalculatePosition();
First = FirstSensor = true;
currentValues = new float[3];
prevValues = new float[3];
currentVelocity = new float[3];
speed = new float[3];
totalDistance = 0.0F;
Toast.makeText(getApplicationContext(),"Service Created",Toast.LENGTH_SHORT).show();
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
mAccelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mMagnetometer = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
//mGyro = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
mLinearAccelertion = sensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
sensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
sensorManager.registerListener(this, mMagnetometer, SensorManager.SENSOR_DELAY_NORMAL);
//sensorManager.registerListener(this, mGyro, SensorManager.SENSOR_DELAY_NORMAL);
sensorManager.registerListener(this, mLinearAccelertion, SensorManager.SENSOR_DELAY_NORMAL);
}
#Override
public void onDestroy(){
Toast.makeText(this, "Service Destroyed", Toast.LENGTH_SHORT).show();
sensorManager.unregisterListener(this);
//sensorManager = null;
super.onDestroy();
}
#Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}
#Override
public void onSensorChanged(SensorEvent event) {
float[] values = event.values;
Sensor mSensor = event.sensor;
if(mSensor.getType() == Sensor.TYPE_ACCELEROMETER){
AccelerometerValue = values;
}
if(mSensor.getType() == Sensor.TYPE_LINEAR_ACCELERATION){
if(First){
prevValues = values;
prevTime = event.timestamp / 1000000000;
First = false;
currentVelocity[0] = currentVelocity[1] = currentVelocity[2] = 0;
distanceX = distanceY= distanceZ = 0;
}
else{
currentTime = event.timestamp / 1000000000.0f;
changeTime = currentTime - prevTime;
prevTime = currentTime;
calculateDistance(event.values, changeTime);
currentAcceleration = (float) Math.sqrt(event.values[0] * event.values[0] + event.values[1] * event.values[1] + event.values[2] * event.values[2]);
CurrentSpeed = (float) Math.sqrt(speed[0] * speed[0] + speed[1] * speed[1] + speed[2] * speed[2]);
CurrentDistanceTravelled = (float) Math.sqrt(distanceX * distanceX + distanceY * distanceY + distanceZ * distanceZ);
CurrentDistanceTravelled = CurrentDistanceTravelled / 1000;
if(FirstSensor){
prevAcceleration = currentAcceleration;
prevDistance = CurrentDistanceTravelled;
prevSpeed = CurrentSpeed;
FirstSensor = false;
}
prevValues = values;
}
}
if(mSensor.getType() == Sensor.TYPE_MAGNETIC_FIELD){
MagnetometerValue = values;
}
if(currentAcceleration != prevAcceleration || CurrentSpeed != prevSpeed || prevDistance != CurrentDistanceTravelled){
if(!FirstSensor)
totalDistance = totalDistance + CurrentDistanceTravelled * 1000;
if (AccelerometerValue != null && MagnetometerValue != null && currentAcceleration != null) {
//Direction
float RT[] = new float[9];
float I[] = new float[9];
boolean success = SensorManager.getRotationMatrix(RT, I, AccelerometerValue,
MagnetometerValue);
if (success) {
float orientation[] = new float[3];
SensorManager.getOrientation(RT, orientation);
float azimut = (float) Math.round(Math.toDegrees(orientation[0]));
currentDirection =(azimut+ 360) % 360;
if( CurrentSpeed > 0.2){
CalculatePosition.calculateNewPosition(getApplicationContext(),currentAcceleration,CurrentSpeed,CurrentDistanceTravelled,currentDirection,totalDistance);
}
}
prevAcceleration = currentAcceleration;
prevSpeed = CurrentSpeed;
prevDistance = CurrentDistanceTravelled;
}
}
}
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
public void calculateDistance (float[] acceleration, float deltaTime) {
float[] distance = new float[acceleration.length];
for (int i = 0; i < acceleration.length; i++) {
speed[i] = acceleration[i] * deltaTime;
distance[i] = speed[i] * deltaTime + acceleration[i] * deltaTime * deltaTime / 2;
}
distanceX = distance[0];
distanceY = distance[1];
distanceZ = distance[2];
}
}
EDIT:
public static void PlotNewPosition(Double newLatitude, Double newLongitude, Float currentDistance,
Float currentAcceleration, Float currentSpeed, Float currentDirection, String dataType) {
LatLng newPosition = new LatLng(newLongitude,newLatitude);
if(dataType == "Sensor"){
tvAcceleration.setText("Speed: " + currentSpeed + " Acceleration: " + currentAcceleration + " Distance: " + currentDistance +" Direction: " + currentDirection + " \n");
map.addMarker(new MarkerOptions()
.position(newPosition)
.title("Position")
.snippet("Sensor Position")
.icon(BitmapDescriptorFactory
.fromResource(R.drawable.line)));
}else if(dataType == "GPSSensor"){
map.addMarker(new MarkerOptions()
.position(newPosition)
.title("PositionCollaborated")
.snippet("GPS Position"));
}
else{
map.addMarker(new MarkerOptions()
.position(newPosition)
.title("Position")
.snippet("New Position")
.icon(BitmapDescriptorFactory
.fromResource(R.drawable.linered)));
}
map.moveCamera(CameraUpdateFactory.newLatLngZoom(newPosition, 18));
}
As per our discussion, since your acceleration is continuously changing, the equations of motion that you have applied shall not give you an accurate answer.
You may have to keep updating your position and velocities as and when you get a new reading for acceleration.
Since this would be highly inefficient, my suggestion would be to call the update function every few seconds and use the average value of acceleration during that period to get the new velocity and position.
I am not quite sure, but my best guess would be around this part:
Double initialVelocity = prevLocation.Speed;
var t = secondsTravelling.TotalSeconds;
var finalvelocity = initialVelocity + Double.Parse(currentAcceleration) * t;
if lets say at the prevLocation the speed was: 27.326... and t==0 and currentAcceleration ==0 (as you said you were idle) the finalvelocity would come down to
var finalvelocity = 27.326 + 0*0;
var finalvelocity == 27.326
If the finalvelocity becomes the speed of the currentlocation, so that previouslocation = currentlocation. This would mean that your finalvelocity might not go down. But then again, there's quite a bit of assumptions here.
Seems like you are making it hard on yourself. You should be able to simply use the Google Play Service Location API and easily access location, direction, speed, etc. accurately.
I would look into using that instead of doing work server side for it.