Quick note, I am new to programming Android applications so feel free to say I'm going about this the entirely wrong way or even to explain things to me like I'm an idiot.
My application is very location dependent. I am using the Google Play Location Services to provide the users current location. Users can store locations in their device which I store using a hashmap. In order to make it more convenient I am trying to make it so the user only has to be within a range of that stored location. My current method to create this range is to essentially use a for loop to scan the user's current location to see if it is in the hashmap.
public String scan(Location local) {
String fLoc = "";
List<String> pLoc = new ArrayList<String>();
String loc = "";
double lat = local.getLatitude();
double lon = local.getLongitude();
lat = (double) Math.round(lat * decimal) / decimal;
lon = (double) Math.round(lon * decimal) / decimal;
for (double x = -8; x < 9; x++) {
double tlat = lat;
double tlon = lon;
tlat = tlat + (x / decimal);
tlat = (double) Math.round(tlat * decimal) / decimal;
for (double y = -8; y < 9; y++) {
tlon = lon;
tlon = tlon + (y / decimal);
tlon = (double) Math.round(tlon * decimal) / decimal;
loc = ("Latitude: " + tlat + " Longitude: " + tlon);
if (locMap.containsKey(loc)) {
pLoc.add(loc);
}
}
}
if (pLoc.isEmpty()) {
lat = local.getLatitude();
lon = local.getLongitude();
lat = (double) Math.round(lat * decimal) / decimal;
lon = (double) Math.round(lon * decimal) / decimal;
loc = ("Latitude: " + lat + " Longitude: " + lon);
fLoc = loc;
} else if (pLoc.size() == 1) {
fLoc = (String) pLoc.toArray()[0];
} else {
Double diff = 0.0;
Double tdiff = 10.0;
for (String l : pLoc) {
diff = 10.0;
String[] parts = l.split(" ");
double dlat = Double.parseDouble(parts[1]) - lat;
if (dlat < 0) {
dlat = dlat * -1;
}
double dlon = Double.parseDouble(parts[5]) - lon;
if (dlon < 0) {
dlon = dlon * -1;
}
diff = dlon + dlat;
if (diff < tdiff) {
tdiff = diff;
fLoc = l;
}
}
}
return fLoc;
}
If no location is close, the user's current location is returned. I feel this is a crude method that is wasteful. What is a better way to find nearby locations? Maybe a for loop through saved location to see if the difference between it and the nearby location is small enough, but this could get costly when the user starts save lots of locations.
Any suggestions?
PS Any tips on adding accurate elevation without barometers?
Related
I'm simulating a polyline with different stops in Java, I have the distance in meters between these two points, the problem is, that I have to go from point A to point B at a speed of 1 to 3 meters per second, and I will need to take the current coordinates I am every 15 min more or less, how can I do that?
The way between the points are straight lines, and all of this is simulated, not happening in a map or something, I just need to print this info every X time, any help?
Example:
I have the coordinates:
LAT: 51.504870000000004 LNG: -0.21533000000000002
and I have to go at that speed to:
LAT: 51.50475 LNG: -0.21571
So, I have to simulate that I go from A to B at 3 meters second, and I need to know my position (lat/lng) while I'm moving between this two points
There's another question that is more or less the same, the difference is that I can't do this with android, is a Java application.
So you know latA, lngA, latB, lngB. From your question, I assume that you know the speed, it's constant, v = 3 m/s. You can get the start time LocalDateTime tA = LocalDateTime.now(); You want to know your coordinates at some moment of time tX.
In order to do this, I would introduce coefLat and coefLng coefficients for transforming coordinates into meters and back. They use mean radius of Earth and translate degrees into radians:
double coefLat = 180 / Math.PI / 6371000;
double coefLng = coefLat / Math.cos(Math.PI * (latA + latB) / 360);
Then calculate distances by Lat and Lng axis and full distance in meters:
double distLat = (latB - latA) / coefLat;
double distLng = (lngB - lngA) / coefLng;
double dist = Math.sqrt(distLat * distLat + distLng * distLng);
double fullTime = dist / v; // Full time needed to pass from A to B in seconds
After some time of moving, find duration and get current coordinates:
LocalDateTime tX = LocalDateTime.now(); // get current time
long dT = Duration.between(tA, tX).getSeconds(); // in seconds
double ratio = dT / fullTime;
double latX = latA + coefLat * ratio * distLat;
double lngX = lngA + coefLng * ratio * distLng;
Please also see this answer
The full code:
public class GetCurrentCoords {
public static void main(String[] args) {
LocalDateTime tA = LocalDateTime.now();
double latA = 51.504870000000004;
double lngA = -0.21533000000000002;
double latB = 51.50475;
double lngB = -0.21571;
double coefLat = 180 / Math.PI / 6371000;
double coefLng = coefLat / Math.cos(Math.PI * (latA + latB) / 360);
double distLat = (latB - latA) / coefLat; // meters
double distLng = (lngB - lngA) / coefLng; // meters
double dist = Math.sqrt(distLat * distLat + distLng * distLng);
System.out.println("distLat = " + distLat + "m; distLng = " + distLng + "m; full dist from A to B = " + dist + "m");
double v = 3;
double fullTime = dist / v; // seconds
System.out.println("full time from A to B = " + fullTime + "s");
// let's move for 4 seconds
try {
TimeUnit.SECONDS.sleep(4);
} catch (InterruptedException ex) {
Logger.getLogger(GetCurrentCoords.class.getName()).log(Level.SEVERE, null, ex);
}
LocalDateTime tX = LocalDateTime.now();
long dT = Duration.between(tA, tX).getSeconds();
double ratio = dT / fullTime;
double latX = latA + coefLat * ratio * distLat;
double lngX = lngA + coefLng * ratio * distLng;
System.out.println("Moving " + dT + " seconds; latX = " + latX + "; lngX = " + lngX);
}
}
I dont get the question clearly but if you want to do something after a given distance you can use this approach
LatLng startPoint=new LatLng(51.504870000000004,-0.21533000000000002);
LatLng endPoin=new LatLng(51.50475,-0.21571);
Location loc1 = new Location("");
loc1.setLatitude(startPoint.latitude);
loc1.setLongitude(startPoint.longitude);
Location loc2 = new Location("");
loc2.setLatitude(endPoint.latitude);
loc2.setLongitude(endPoint.longitude);
float distance = loc1.distanceTo(loc2);
//instead of if you can use for loop
if (distance <= 100) {
//do something, like get the coordinates
} else {
//do something
}
I am making a Speed Converter app. There's a problem in my if statement. I want my distance/hour/minute/second to be equals to 0 when it is left blank so that it will still compute my formulas. But unfortunately my app keeps crashing when I hit the compute button. Any kind of suggestion or revision will help. Thank you.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
distance = (EditText)findViewById(R.id.distance);
hour = (EditText)findViewById(R.id.hour);
minute = (EditText)findViewById(R.id.minute);
second = (EditText)findViewById(R.id.second);
kph = (TextView)findViewById(R.id.kph);
kps = (TextView)findViewById(R.id.kps);
mm = (TextView)findViewById(R.id.mm);
}
public void computeClick(View view) {
String d = distance.getText().toString().trim();
String h = hour.getText().toString().trim();
String m = minute.getText().toString().trim();
String s = second.getText().toString().trim();
Double dis = Double.parseDouble(d);
Double hr = Double.parseDouble(h);
Double min = Double.parseDouble(m);
Double sec = Double.parseDouble(s);
if (d.equals("")) {
distance.setText("0");
}
if (h.equals("")) {
hour.setText("0");
}
if (m.equals("")) {
minute.setText("0");
}
if (s.equals("")) {
second.setText("0");
}
Double dtok = dis / 1000;
Double mtoh = min / 60;
Double stoh = sec / 3600;
Double htoh = hr / 1;
Double htos = hr * 3600;
Double mtos = min * 60;
Double stos = sec / 1;
Double htom = hr * 60;
Double stom = sec / 60;
Double mtom = min / 1;
Double totaltimekph = mtoh + stoh + htoh;
Double totalkph = dtok / totaltimekph;
kph.setText(Double.toString(totalkph));
Double totaltimekps = htos + mtos + stos;
Double totalkps = dtok / totaltimekps;
kps.setText(Double.toString(totalkps));
Double totaltimempm = htom + stom + mtom;
Double totalmpm = dis / totaltimempm;
mm.setText(Double.toString(totalmpm));
}
You should not call Double.parseDouble() if the EditText value is empty. Instead, assign the value as 0 to the variable.
Don't check this way
d.equals("")
Use this method
d.isEmpty()
And same for all other EditText variables.
I'm trying to come up with function that could fill in gps coordinates between two points every second. There are few posts about this here, but I couldn't find something complete. The closest answer I found was:
Interpolate between 2 GPS locations based on walking speed
I modified one of the answer using the bearing. However, it still doesn't seem to work. Especially I think the distance calculation is wrong. Could someone look at the code below and change?
Thank you!
import java.util.ArrayList;
public class Test {
double radius = 6371;
public Test() {
Location start = new Location(lat, lon);
Location end = new Location(lat, lon);
double speed = 1.39;
double distance = CalculateDistanceBetweenLocations(start, end);
double duration = distance / speed;
System.out.println(distance + ", " + speed + ", " + duration);
ArrayList<Location> locations = new ArrayList<Location>();
for (double i = 0; i < duration; i += 1.0) {
double bearing = CalculateBearing(start, end);
double distanceInKm = speed / 1000;
Location intermediaryLocation = CalculateDestinationLocation(start, bearing, distanceInKm);
locations.add(intermediaryLocation);
System.out.println(intermediaryLocation.latitude + ", " + intermediaryLocation.longitude);
start = intermediaryLocation;
}
}
double DegToRad(double deg) {
return (deg * Math.PI / 180);
}
double RadToDeg(double rad) {
return (rad * 180 / Math.PI);
}
double CalculateBearing(Location startPoint, Location endPoint) {
double lat1 = DegToRad(startPoint.latitude);
double lat2 = DegToRad(endPoint.latitude);
double deltaLon = DegToRad(endPoint.longitude - startPoint.longitude);
double y = Math.sin(deltaLon) * Math.cos(lat2);
double x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(deltaLon);
double bearing = Math.atan2(y, x);
return (RadToDeg(bearing) + 360) % 360;
}
Location CalculateDestinationLocation(Location point, double bearing, double distance) {
distance = distance / radius;
bearing = DegToRad(bearing);
double lat1 = DegToRad(point.latitude);
double lon1 = DegToRad(point.longitude);
double lat2 = Math
.asin(Math.sin(lat1) * Math.cos(distance) + Math.cos(lat1) * Math.sin(distance) * Math.cos(bearing));
double lon2 = lon1 + Math.atan2(Math.sin(bearing) * Math.sin(distance) * Math.cos(lat1),
Math.cos(distance) - Math.sin(lat1) * Math.sin(lat2));
lon2 = (lon2 + 3 * Math.PI) % (2 * Math.PI) - Math.PI;
return new Location(RadToDeg(lat2), RadToDeg(lon2));
}
double CalculateDistanceBetweenLocations(Location startPoint, Location endPoint) {
double lat1 = DegToRad(startPoint.latitude);
double lon1 = DegToRad(startPoint.longitude);
double lat2 = DegToRad(endPoint.latitude);
double lon2 = DegToRad(endPoint.longitude);
double deltaLat = lat2 - lat1;
double deltaLon = lon2 - lon1;
double a = Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2)
+ Math.cos(lat1) * Math.cos(lat2) * Math.sin(deltaLon / 2) * Math.sin(deltaLon / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - 1));
return (radius * c);
}
public static void main(String[] args) {
new Test();
}
class Location {
public double latitude, longitude;
public Location(double lat, double lon) {
latitude = lat;
longitude = lon;
}
}
}
You have a typing error in line
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - 1));
It should be
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
Your method CalculateDistanceBetweenLocations contains an this line:
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - 1));
which is equivalent to
double c = 2 * Math.atan2(Math.sqrt(a), 0.0);
which means that the result of Math.atan2 is always pi, independent of the value of a as long as a is positive.
Therefore CalculateDistanceBetweenLocations always returns 20015.086796020572 independent of the input coordinates.
Using GPS points I am calculating by holding previous and current points with
location1.distanceTo(location2) by adding each time to a variable on some time diff to get traveled distance. Is it good approach to get vehicle movement distance? Is any better approach to get accurate travel distance during moving vehicle?
Use the following code. I hope it will help.
public double CalculationByDistance(LatLng StartP, LatLng EndP) {
int Radius = 6371;// radius of earth in Km
double lat1 = StartP.latitude;
double lat2 = EndP.latitude;
double lon1 = StartP.longitude;
double lon2 = EndP.longitude;
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;
}
float[] results = new float[1];
Location.distanceBetween(oldPosition.latitude, oldPosition.longitude,
newPosition.latitude, newPosition.longitude, results);
This is my current code:
public class Sunpos {
final private double Pi = Math.PI;
final private double eul = 2.71828182845904523552 ;
final private double sonauf = 90;
final private double RAD = 0.017453292519943295769236907684886;
public double sunrisefinal (double Breitengrad, double Laengengrad, int tagzahl, int sommerzeit, int nacht) {
double lngHour = Laengengrad/15;
double t = tagzahl + ((6 - lngHour)/24);
// double ab = tagzahl + ((18 - lngHour)/24);
double M = (0.9856 * t) - 3.289;
double L = M + (1.916 * Math.sin(M)) + (0.020 * Math.sin(2 * M)) + 282.634;
if (L >= 359) { L -= 360; }
else if (L < 0) { L += 360; }
double RA = (Math.atan(0.91764 * Math.tan(Pi/180)*L));
if (RA >= 359) { RA -= 360; }
else if (RA < 0) { RA += 360; }
double Lquadrant = (Math.floor(L/90)*90);
double RAquadrant = (Math.floor(RA/90))*90;
RA = RA + (Lquadrant - RAquadrant);
RA = RA/15;
double sinDec = 0.39782 * Math.sin((Pi/180)*L);
double cosDec = (180/Pi)*(Math.cos(Math.asin(sinDec)));
double cosH = (Math.cos((Pi/180)*sonauf)-(sinDec*Math.sin((Pi/180)*Breitengrad)))/(cosDec * Math.cos((Pi/180)*Breitengrad));
double H = 360 - Math.acos(cosH);
H /= 15;
double T = H + RA -(0.06571 * t) - 6.622;
double UTC = T - lngHour;
if (UTC >= 23) { UTC -= 24; }
else if (UTC < 0) { UTC += 24; }
double locTime = UTC; // Fuer die schweiz!
System.out.println(locTime);
return(0);
}
The inputs are the following: ( 50, 10, 294, 1, 0). The last 2 can be ignored.
Now I am basing this on the following page:
http://williams.best.vwh.net/sunrise_sunset_algorithm.htm
The code should be complete according to the site, but I don't get anywhere near the supposed results. I should get around 7.5 for today but I'm getting a 9.358.
Now, that might be because something with radiants/degrees? I can't quite get my Mind into that, as I've been trying to insert those converters (Pi/180) into the code, without any usable result.
Can anyone tell me where to put them or point me in the right direction? I've spent waaaay too much time on this already, and now I'm so close.
I'll just post my implementation here in case people need it (ported from the same source as yours)
https://gist.github.com/zhong-j-yu/2232343b14a5b5ef5b9d
public class SunRiseSetAlgo
{
static double calcSunrise(int dayOfYear, double localOffset, double latitude, double longitude)
{
return calc(dayOfYear, localOffset, latitude, longitude, true);
}
static double calcSunset(int dayOfYear, double localOffset, double latitude, double longitude)
{
return calc(dayOfYear, localOffset, latitude, longitude, false);
}
// http://williams.best.vwh.net/sunrise_sunset_algorithm.htm
static double calc(int dayOfYear, double localOffset, double latitude, double longitude, boolean rise)
{
//1. first calculate the day of the year
// int N1 = floor(275 * month / 9.0);
// int N2 = floor((month + 9) / 12.0);
// int N3 = (1 + floor((year - 4 * floor(year / 4.0) + 2) / 3.0));
// int N = N1 - (N2 * N3) + day - 30;
int N = dayOfYear;
//2. convert the longitude to hour value and calculate an approximate time
double lngHour = longitude / 15;
double t = rise?
N + (( 6 - lngHour) / 24) :
N + ((18 - lngHour) / 24);
//3. calculate the Sun's mean anomaly
double M = (0.9856 * t) - 3.289;
//4. calculate the Sun's true longitude
double L = M + (1.916 * sin(M)) + (0.020 * sin(2 * M)) + 282.634;
L = mod(L, 360);
//5a. calculate the Sun's right ascension
double RA = atan(0.91764 * tan(L));
RA = mod(RA, 360);
//5b. right ascension value needs to be in the same quadrant as L
double Lquadrant = (floor( L/90)) * 90;
double RAquadrant = (floor(RA/90)) * 90;
RA = RA + (Lquadrant - RAquadrant);
//5c. right ascension value needs to be converted into hours
RA = RA / 15;
//6. calculate the Sun's declination
double sinDec = 0.39782 * sin(L);
double cosDec = cos(asin(sinDec));
//7a. calculate the Sun's local hour angle
double zenith = 90 + 50.0/60;
double cosH = (cos(zenith) - (sinDec * sin(latitude))) / (cosDec * cos(latitude));
if (cosH > 1)
throw new Error("the sun never rises on this location (on the specified date");
if (cosH < -1)
throw new Error("the sun never sets on this location (on the specified date");
//7b. finish calculating H and convert into hours
double H = rise?
360 - acos(cosH) :
acos(cosH);
H = H / 15;
//8. calculate local mean time of rising/setting
double T = H + RA - (0.06571 * t) - 6.622;
//9. adjust back to UTC
double UT = T - lngHour;
//10. convert UT value to local time zone of latitude/longitude
double localT = UT + localOffset;
localT = mod(localT, 24);
return localT;
}
static int floor(double d){ return (int)Math.floor(d); }
static double sin(double degree)
{
return Math.sin(degree*Math.PI/180);
}
static double cos(double degree)
{
return Math.cos(degree*Math.PI/180);
}
static double tan(double degree)
{
return Math.tan(degree*Math.PI/180);
}
static double atan(double x)
{
return Math.atan(x) *180/Math.PI;
}
static double asin(double x)
{
return Math.asin(x) *180/Math.PI;
}
static double acos(double x)
{
return Math.acos(x) *180/Math.PI;
}
static double mod(double x, double lim)
{
return x - lim * floor(x/lim);
}
}
Everone seems to link to this http://williams.best.vwh.net/sunrise_sunset_algorithm.htm
which doesn't exist anymore. Why not try something that gets updated once in a while like https://en.wikipedia.org/wiki/Sunrise_equation
Then if you like you could help edit it to make it better.