I have implemented the motion detection of user in my app by calculating its lat-long getting from googleAPIClient in which i am doing
1)get location of user in every 15 sec
2)the location before 15 sec and after 15 sec i am calculating the speed using formula mentioned below
`private double getSpeed(Location currentLocation, Location oldLocation) {
if (currentLocation != null && oldLocation != null) {
double newLat = currentLocation.getLatitude();
double newLon = currentLocation.getLongitude();
double oldLat = oldLocation.getLatitude();
double oldLon = oldLocation.getLongitude();
if (currentLocation.hasSpeed()) {
return currentLocation.getSpeed();
} else {
double radius = 6371000;
double dLat = Math.toRadians(newLat - oldLat);
double dLon = Math.toRadians(newLon - oldLon);
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(Math.toRadians(newLat)) * Math.cos(Math.toRadians(oldLat)) *
Math.sin(dLon / 2) * Math.sin(dLon / 2);
double c = 2 * Math.asin(Math.sqrt(a));
double distance = ((Math.round(radius * c)) * 36) /1.609344; // convert meter to km as m*60*60/s*1000 thn convert whole into miles;
CommonMethods.showLogs("BaseActivity.this", "getSpeed distance == " + distance);
double timeDifferent = (currentLocation.getTime() - oldLocation.getTime()) * 10; //convert mili sec to hr
CommonMethods.showLogs("BaseActivity.this", "getSpeed time == " + timeDifferent);
return distance / timeDifferent;
}
}
return 0;
}`
3) after that check if speed is more than 3mph than do my stuffs
4) it is working fine when tested in a car and bus but when tested in 2
wheeler it is not working properly some times it is some time it is not
i don't get the problem what is wrong in my case please help!!
Thanks!!
Related
I have a app where I am showing the nearest event (place) distance in km using the Latitude and Longitude. Users latitude and longitude is variable but events latitude and longitude are fixed.However, I am not able to get the correct distance is km. for example correct distance is 6.7 km in google map but its showing 8663.90 km. I am novice in android so unable to get the solution. any help will be great!! my codes are
{ double doubleInstance = d.getDistance(Lat1, Lon1, d.getLatitude(), d.getLongitude(), "N");
String dInstance = String.format("%.2f",doubleInstance);
lblview1.setText(" " + String.valueOf(dInstance) + " Km"); }
and
{ public double getDistance(double lat1, double lon1, double lat2, double lon2, String unit) {
int Radius = 6371;// radius of earth in Km
double dLat = Math.toRadians(lat2 - lat1);
double dLon = Math.toRadians(lon2 - lon1);
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
+ Math.cos(Math.toRadians(lat1))
* Math.cos(Math.toRadians(lat2)) * Math.sin(dLon / 2)
* Math.sin(dLon / 2);
double c = 2 * Math.asin(Math.sqrt(a));
double valueResult = Radius * c;
double km = valueResult / 1;
DecimalFormat newFormat = new DecimalFormat("####");
int kmInDec = Integer.valueOf(newFormat.format(km));
double meter = valueResult % 1000;
int meterInDec = Integer.valueOf(newFormat.format(meter));
Log.i("Radius Value", "" + valueResult + " KM " + kmInDec
+ " Meter " + meterInDec);
return Radius * c;
} }
Set your Event location. And get your current location using location manager.
double latitude=lat;
double longitude=lng;
float distance=0;
Location crntLocation=new Location("crntlocation");
crntLocation.setLatitude(currentLatitude);
crntLocation.setLongitude(currentLongitude);
Location eventLocation=new Location("eventlocation");
eventLocation.setLatitude(latitude);
eventLocation.setLongitude(longitude);
//float distance = crntLocation.distanceTo(eventLocation); in meters
distance =crntLocation.distanceTo(eventLocation) / 1000; // in kms
Use Location class method to get distance between two coordinates like;
Location.distanceBetween(obj.getLatitude(), obj.getLongitude(),
mapCircle.getCenter().latitude, mapCircle.getCenter().longitude, distance);
To be honest I've just started with programming but for the life of me I can't figure out where I'm wrong.
the math is:
10$ / 2 hours
tips per hour = 5 (i get 0.2)
waiter 1 pay = 10 (i get 0.4?)
screenshot
The Calculation in MainActivity:
double resultTotalHours = cWaiter1Hours + cWaiter2Hours + cWaiter3Hours + cWaiter4Hours;
double calcTipsPerHour = resultTotalHours / totalTips;
double resultBarsCut = (totalTips * (cBarCutInput / 100));
double resultTaxDeposit = resultTotalHours * 3;
double resultTipsPerHour = (totalTips - resultBarsCut - resultTaxDeposit) / resultTotalHours;
double resultWaiter1Pay = cWaiter1Hours * resultTipsPerHour;
double resultWaiter2Pay = cWaiter2Hours * resultTipsPerHour;
double resultWaiter3Pay = cWaiter3Hours * resultTipsPerHour;
double resultWaiter4Pay = cWaiter4Hours * resultTipsPerHour;
double resultWaiter1NoTax = cWaiter1Hours * calcTipsPerHour;
double resultWaiter2NoTax = cWaiter2Hours * calcTipsPerHour;
double resultWaiter3NoTax = cWaiter3Hours * calcTipsPerHour;
double resultWaiter4NoTax = cWaiter4Hours * calcTipsPerHour;
Casting the results to the TextViews:
if (calcTipsPerHour <= 30) {
totalHoursView.setText(Double.toString(resultTotalHours));
tipsPerHourView.setText(Double.toString(calcTipsPerHour));
barsCutView.setText(Double.toString(0));
taxDepositView.setText(Double.toString(0));
waiter1Pay.setText(Double.toString(resultWaiter1NoTax));
waiter2Pay.setText(Double.toString(resultWaiter2NoTax));
waiter3Pay.setText(Double.toString(resultWaiter3NoTax));
waiter4Pay.setText(Double.toString(resultWaiter4NoTax));
} else {
totalHoursView.setText(Double.toString(resultTotalHours));
tipsPerHourView.setText(Double.toString(resultTipsPerHour));
barsCutView.setText(Double.toString(resultBarsCut));
taxDepositView.setText(Double.toString(resultTaxDeposit));
waiter1Pay.setText(Double.toString(resultWaiter1Pay));
waiter2Pay.setText(Double.toString(resultWaiter2Pay));
waiter3Pay.setText(Double.toString(resultWaiter3Pay));
waiter4Pay.setText(Double.toString(resultWaiter4Pay));
}
The problem is here:
double calcTipsPerHour = resultTotalHours / totalTips;
This is currently doing 2 / 10 = 0.2.
You want to do the reciprocal:
double calcTipsPerHour = totalTips / resultTotalHours;
This should also fix your waiter's pay
You put hours in the numerator and tips in the denominator so you are getting the inverse of what you want: hours/tip
What you want is:
double calcTipsPerHour = totalTips / resultTotalHours;
I want to find out if the user in specific region using GPS data and consider with accuracy info to reduce error, because the program will prompt an alert if user definitely out of the region.
GPS sensor return latitude, longitude and accuracy(in meter), I can draw a circle using those data:
135.500908,34.661964,30.0
There're array of coordinates in sequence represent the specific region:
135.500350,34.667011
135.506101,34.666853
135.505972,34.663076
135.505135,34.663111
135.504942,34.662387
135.504084,34.662440
135.504062,34.663146
135.502968,34.663217
135.502689,34.663764
135.502431,34.664205
135.502110,34.664646
135.501680,34.665105
135.501509,34.665246
135.500844,34.665229
135.500371,34.665511
My idea is to find out if any collisions of the polygon with the circle by using line-circle collisions detection algorithm, but it looks something wrong in my code, and seems I can't directly use that info due to radius/degree, could anyone help me out? Or let me know if any more simple solution?
public static boolean possiblyInside(List<Double> arrayX, List<Double> arrayY, double locationX, double locationY, double locationAccuracy) {
if (arrayX.size() != arrayY.size()) {
throw new IllegalArgumentException("Array length not equal");
}
boolean anyCircleLineIntersection = false;
if (arrayX.size() > 1) {
for (int i = 0; i < arrayX.size(); i++) {
double p1x = i == 0 ? arrayX.get(arrayX.size() - 1) : arrayX.get(i - 1);
double p1y = i == 0 ? arrayY.get(arrayY.size() - 1) : arrayY.get(i - 1);
double p2x = arrayX.get(i);
double p2y = arrayY.get(i);
if (circleLineIntersection(p1x, p1y, p2x, p2y, locationX, locationY, locationAccuracy)) {
anyCircleLineIntersection = true;
break;
}
}
}
return anyCircleLineIntersection;
}
private static boolean circleLineIntersection(double p1X, double p1Y, double p2X, double p2Y, double centerX, double centerY, double locationAccuracy) {
double rad = (180 / Math.PI);
double r = (locationAccuracy / 1000);
p1X = p1X * rad;
p1Y = p1Y * rad;
p2X = p2X * rad;
p2Y = p2Y * rad;
centerX = centerX * rad;
centerY = centerY * rad;
// Transform to local coordinates
double localP1X = p1X - centerX;
double localP1Y = p1Y - centerY;
double localP2X = p2X - centerX;
double localP2Y = p2Y - centerY;
// Pre-calculate this value. We use it often
double pDiffX = localP2X - localP1X;
double pDiffY = localP2Y - localP1Y;
double a = (pDiffX) * (pDiffX) + (pDiffY) * (pDiffY);
double b = 2 * ((pDiffX * localP1X) + (pDiffY * localP1Y));
double c = (localP1X * localP1X) + (localP1Y * localP1Y) - (r * r);
double delta = b * b - (4 * a * c);
return delta >= 0.0;
}
There is a method called Geofencing. Google already provides such functionality for you. And you don't have to deal with all these complex calculations.
You can fire events when the user entered a specific area / exited a specific area / after staying for some time in a specific area. Or you can make different combinations.
Here is an article of how you can use Geofencing. It consists of 4 separated articles.
Thank you for Todor Kostov's answer.
I know Android has provided Geofencing API, but it is not a perfect fit for my situation due to its implementation and limitations, and I would like to sync the algorithm with iOS version app as well. (Even I know the algorithm are not good as iOS or Android provided, and it also looks a bit silly).
Finally, I solved the problem in this way:
Ensure current location not inside the polygon (use point-in-polygon algorithm)
Loop through all line segment of the region polygon, find out the
closest coordinate(PointA) to the current location(PointB)
Calculate the distance between PointA and PointB, convert it to meter(X)
If X > location accuracy (also in meter), the user is definitely out of the particular region
p.s. I'm not good at math and geolocation, point out if any incorrect
public static boolean possiblyInside(List<Double> arrayX, List<Double> arrayY, double locationX, double locationY, double locationAccuracy) {
if (arrayX.size() != arrayY.size()) {
throw new IllegalArgumentException("Array length not equal");
}
if (arrayX.size() < 3) {
return false;
}
double minimumDistance = Double.MAX_VALUE;
for (int i = 0; i < arrayX.size(); i++) {
double p1x = i == 0 ? arrayX.get(arrayX.size() - 1) : arrayX.get(i - 1);
double p1y = i == 0 ? arrayY.get(arrayY.size() - 1) : arrayY.get(i - 1);
double p2x = arrayX.get(i);
double p2y = arrayY.get(i);
Coordinate closest = getClosestPointOnLine(p1x, p1y, p2x, p2y, locationX, locationY);
double currentDistance = distanceMeterBetweenPoints(closest.latitude, closest.longitude, locationX, locationY);
if (currentDistance < minimumDistance) {
minimumDistance = currentDistance;
}
}
return (minimumDistance <= locationAccuracy);
}
private static Coordinate getClosestPointOnLine(double sx1, double sy1, double sx2, double sy2, double px, double py) {
double xDelta = sx2 - sx1;
double yDelta = sy2 - sy1;
if ((xDelta == 0) && (yDelta == 0)) {
throw new IllegalArgumentException("Line start equals line end");
}
double u = ((px - sx1) * xDelta + (py - sy1) * yDelta) / (xDelta * xDelta + yDelta * yDelta);
final Coordinate closestPoint;
if (u < 0.0) {
closestPoint = new Coordinate(sx1, sy1);
} else if (u > 1.0) {
closestPoint = new Coordinate(sx2, sy2);
} else {
closestPoint = new Coordinate((int) Math.round(sx1 + u * xDelta), (int) Math.round(sy1 + u * yDelta));
}
return closestPoint;
}
public static double distanceMeterBetweenPoints(double aX, double aY, double bX, double bY) {
double rad = Math.PI / 180;
int r = 6371;
double dLat = (aX - bX) * rad;
double dLng = (aY - bY) * rad;
double x = Math.pow(Math.sin(dLat / 2), 2) + Math.cos(aX * rad) * Math.cos(bX * rad) * Math.pow(Math.sin(dLng / 2), 2);
double y = 2 * Math.atan2(Math.sqrt(x), Math.sqrt(1 - x));
return r * y * 1000;
}
I'm trying to figure out how to represent geographic locations, and I can't seem to find any relevant classes in the SE documentation.
I would like to do something like this:
Location locA = new Location(aa.aaaaaaa, bb.bbbbbbb); //lat/long coordinates
Location locB = .....
int meters = locA.distanceTo(locB);
Ideally I would want something like the Android Location since most of my location data will be sent from android devices anyway. From my understanding it contains information about accuracy, latitude and speed, which would be useful (but not required).
I have an idea of how to implement it myself, but an open source alternative would save me some time.
It would also be extremely helpful if I could do some IP/Location lookup. But I guess that's a whole other issue.
Here is a method to calculate distance between 2 points, taken from Android Location class with small modification. It looks a little bit complicated--this is because it uses Vincenty's formulae to perform iterative calculations on WGS84 ellipsoid:
/** distance between 2 geographic points on Earth, in km **/
public static double geoDistance(GeoPoint gp1, GeoPoint gp2) {
// Based on http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf
// using the "Inverse Formula" (section 4)
int MAXITERS = 20;
// Convert lat/long to radians
double lat1 = gp1.getLat() * Math.PI / 180.0;
double lat2 = gp2.getLat() * Math.PI / 180.0;
double lon1 = gp1.getLon() * Math.PI / 180.0;
double lon2 = gp2.getLon() * Math.PI / 180.0;
double a = 6378.137; // WGS84 major axis
double b = 6356.7523142; // WGS84 semi-major axis
double f = (a - b) / a;
double aSqMinusBSqOverBSq = (a * a - b * b) / (b * b);
double L = lon2 - lon1;
double A = 0.0;
double U1 = Math.atan((1.0 - f) * Math.tan(lat1));
double U2 = Math.atan((1.0 - f) * Math.tan(lat2));
double cosU1 = Math.cos(U1);
double cosU2 = Math.cos(U2);
double sinU1 = Math.sin(U1);
double sinU2 = Math.sin(U2);
double cosU1cosU2 = cosU1 * cosU2;
double sinU1sinU2 = sinU1 * sinU2;
double sigma = 0.0;
double deltaSigma = 0.0;
double cosSqAlpha = 0.0;
double cos2SM = 0.0;
double cosSigma = 0.0;
double sinSigma = 0.0;
double cosLambda = 0.0;
double sinLambda = 0.0;
double lambda = L; // initial guess
for (int iter = 0; iter < MAXITERS; iter++) {
double lambdaOrig = lambda;
cosLambda = Math.cos(lambda);
sinLambda = Math.sin(lambda);
double t1 = cosU2 * sinLambda;
double t2 = cosU1 * sinU2 - sinU1 * cosU2 * cosLambda;
double sinSqSigma = t1 * t1 + t2 * t2; // (14)
sinSigma = Math.sqrt(sinSqSigma);
cosSigma = sinU1sinU2 + cosU1cosU2 * cosLambda; // (15)
sigma = Math.atan2(sinSigma, cosSigma); // (16)
double sinAlpha = (sinSigma == 0) ? 0.0 :
cosU1cosU2 * sinLambda / sinSigma; // (17)
cosSqAlpha = 1.0 - sinAlpha * sinAlpha;
cos2SM = (cosSqAlpha == 0) ? 0.0 :
cosSigma - 2.0 * sinU1sinU2 / cosSqAlpha; // (18)
double uSquared = cosSqAlpha * aSqMinusBSqOverBSq; // defn
A = 1 + (uSquared / 16384.0) * // (3)
(4096.0 + uSquared *
(-768 + uSquared * (320.0 - 175.0 * uSquared)));
double B = (uSquared / 1024.0) * // (4)
(256.0 + uSquared *
(-128.0 + uSquared * (74.0 - 47.0 * uSquared)));
double C = (f / 16.0) *
cosSqAlpha *
(4.0 + f * (4.0 - 3.0 * cosSqAlpha)); // (10)
double cos2SMSq = cos2SM * cos2SM;
deltaSigma = B * sinSigma * // (6)
(cos2SM + (B / 4.0) *
(cosSigma * (-1.0 + 2.0 * cos2SMSq) -
(B / 6.0) * cos2SM *
(-3.0 + 4.0 * sinSigma * sinSigma) *
(-3.0 + 4.0 * cos2SMSq)));
lambda = L +
(1.0 - C) * f * sinAlpha *
(sigma + C * sinSigma *
(cos2SM + C * cosSigma *
(-1.0 + 2.0 * cos2SM * cos2SM))); // (11)
double delta = (lambda - lambdaOrig) / lambda;
if (Math.abs(delta) < 1.0e-12) {
break;
}
}
return b * A * (sigma - deltaSigma);
}
GeoPoint class looks like the following:
/**
* Immutable point in geo coordinates (latitude, longitude) with accuracy in km
*/
public class GeoPoint {
private final double lat;
private final double lon;
private final double accuracy;
/**
* New geo point without accuracy
*/
public GeoPoint(double lat, double lon){
this(lat, lon, -1d);
}
/**
* New geo point with specified accuracy
* #param accuracy accuracy in km
*/
public GeoPoint(double lat, double lon, double accuracy){
this.lat = lat;
this.lon = lon;
this.accuracy = accuracy < 0 ? -1d : accuracy;
}
public double getLat(){
return this.lat;
}
public double getLon(){
return this.lon;
}
/**
* #return accuracy in km. If < 0, accuracy is not defined
*/
public double getAccuracy(){
return this.accuracy;
}
#Override
public String toString(){
return "lat = " + this.lat + "; lon = " + this.lon + (this.accuracy < 0 ? "" : ("; accuracy = " + this.accuracy));
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof GeoPoint) || o == null) return false;
GeoPoint g = (GeoPoint) o;
return g.lat == this.lat && g.lon == this.lon && g.accuracy == this.accuracy;
}
}
In order to emulate Excel's rate function, I'm using the Apache POI rate function I grabbed from the svn:
private double calculateRate(double nper, double pmt, double pv, double fv, double type, double guess) {
//FROM MS http://office.microsoft.com/en-us/excel-help/rate-HP005209232.aspx
int FINANCIAL_MAX_ITERATIONS = 20; //Bet accuracy with 128
double FINANCIAL_PRECISION = 0.0000001; //1.0e-8
double y, y0, y1, x0, x1 = 0, f = 0, i = 0;
double rate = guess;
if (Math.abs(rate) < FINANCIAL_PRECISION) {
y = pv * (1 + nper * rate) + pmt * (1 + rate * type) * nper + fv;
}
else {
f = Math.exp(nper * Math.log(1 + rate));
y = pv * f + pmt * (1 / rate + type) * (f - 1) + fv;
}
y0 = pv + pmt * nper + fv;
y1 = pv * f + pmt * (1 / rate + type) * (f - 1) + fv;
// Find root by the Newton secant method
i = x0 = 0.0;
x1 = rate;
while ((Math.abs(y0 - y1) > FINANCIAL_PRECISION) && (i < FINANCIAL_MAX_ITERATIONS)) {
rate = (y1 * x0 - y0 * x1) / (y1 - y0);
x0 = x1;
x1 = rate;
if (Math.abs(rate) < FINANCIAL_PRECISION) {
y = pv * (1 + nper * rate) + pmt * (1 + rate * type) * nper + fv;
}
else {
f = Math.exp(nper * Math.log(1 + rate));
y = pv * f + pmt * (1 / rate + type) * (f - 1) + fv;
}
y0 = y1;
y1 = y;
++i;
}
return rate;
}
For calculateRate(120, 28.1, -2400, 0, 0, 0.1)), the output is the same as Excel: 0.599
But if I try the same calculation, this time with the values:
calculateRate(360, 15.9, -2400, 0, 0, 0.1))
In Excel I get 0.580, and the program returns -1.1500428517726355. Any hints?
There are a bunch of things that are wrong with this code that you have pasted in your question.
It assumes that a rate is always found (not true) and makes no provision for instances when a rate is not found.
Some of the statements will throw an error which could have been avoided by using a more appropriate programming statement. For instance, take the following statement from your code:
f = Math.exp(nper * Math.log(1 + rate));
This will throw an error when attempting to find Log of a negative or zero value. It could have been rewritten as
f = Math.pow(1 + rate, nper);
The comment in iterative calculations states that it is programming the secant method, yet the iterative calculations are checked for convergence of the wrong variable. It is testing for convergence of a future value when it should be testing for convergence of the interest rate.
I copy pasted your code in Notepad and removed the variable declaration of Java and replaced these with JavaScript variable declarations to test the code with your sample data. And just as I said, the code stops at the second iteration since the difference of future values goes out of error bound and since there is no test in place to see whether a rate is found, the code returns the interest rate as is and one which is wrong.
I am not sure why this code works in instances where it does report a correct rate as is the case with first data set. I would suggest re-coding of the function in a correct manner.
public double rate(double nper, double pmt, double pv)
{
//System.out.println("function rate : " + nper + " " + pmt + " pv " + pv);
double error = 0.0000001;
double high = 1.00;
double low = 0.00;
double rate = (2.0 * (nper * pmt - pv)) / (pv * nper);
while(true) {
// Check for error margin
double calc = Math.pow(1 + rate, nper);
calc = (rate * calc) / (calc - 1.0);
calc -= pmt / pv;
if (calc > error) {
// Guess is too high, lower the guess
high = rate;
rate = (high + low) / 2;
}
else if (calc < -error) {
// Guess is too low, higher the guess.
low = rate;
rate = (high + low) / 2;
}
else {
// Acceptable guess
break;
}
}
//System.out.println("Rate : " + rate);
return rate;
}
Example: =RATE(60, 2112500, 65000000) returns 0.025198; the same with Excel (correct).