See this illustration:
What I would like to know is:
How to create an area (circle) when given a latitude and longitude and the distance (10 kilometers)
How to check (calculate) if a latitude and longitude is either inside or outside the area
I would prefer if you can give me code example in Java or specifically for Android with Google Maps API V2
What you basically need, is the distance between two points on the map:
float[] results = new float[1];
Location.distanceBetween(centerLatitude, centerLongitude, testLatitude, testLongitude, results);
float distanceInMeters = results[0];
boolean isWithin10km = distanceInMeters < 10000;
If you have already Location objects:
Location center;
Location test;
float distanceInMeters = center.distanceTo(test);
boolean isWithin10km = distanceInMeters < 10000;
Here is the interesting part of the API used:
https://developer.android.com/reference/android/location/Location.html
Check this:
private boolean isMarkerOutsideCircle(LatLng centerLatLng, LatLng draggedLatLng, double radius) {
float[] distances = new float[1];
Location.distanceBetween(centerLatLng.latitude,
centerLatLng.longitude,
draggedLatLng.latitude,
draggedLatLng.longitude, distances);
return radius < distances[0];
}
Have you gone through the new GeoFencing API. It should help you. Normal implementation takes a lot of time. This should help you implementing it easily.
see https://developer.android.com/reference/android/location/Location.html
Location areaOfIinterest = new Location;
Location currentPosition = new Location;
areaOfIinterest.setLatitude(aoiLat);
areaOfIinterest.setLongitude(aoiLong);
currentPosition.setLatitude(myLat);
currentPosition.setLongitude(myLong);
float dist = areaOfIinterest.distanceTo(currentPosition);
return (dist < 10000);
Location didn't work for me, here's what I did.
import 'dart:math' show cos, sqrt, asin;
double calculateDistanceBetweenTwoLatLongsInKm(
double lat1, double lon1, double lat2, double 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));
}
Then just check if that distance is more (outside) or less (inside) than your radius in KM
Just in case if anyone is using GoogleMap and tried to apply location range by long&lat. You may try google.maps.Circle()
i.e. (mkr is your marker)
let yourcircle = new google.maps.Circle({
strokeColor: "#0079C3",
strokeOpacity: .8,
strokeWeight: 2,
fillColor: "#0079C3",
fillOpacity: 0.2,
map: this.map,
center: {'lat':your latitude, 'lng':your longitude},
radius: Math.sqrt(your distance range) * 1000,
});
Kotlin version
Using instance method distanceTo, something like this in a form of an extension function:
fun Location.checkIsInBound(radius: Double,center:Location):Boolean
= this.distanceTo(center)<radius
Usage example:
fusedLocationClient.lastLocation
.addOnSuccessListener { location : Location? ->
val isWithin2km = location?.checkIsInBound(2000.0,center) }
Besides using Location API's distanceTo or distanceBetween as stated in the above answers, You could also use Google Map Utility Library's SphericalUtil's computeDistanceBetween as well, however it takes LatLng as input.
If you mean by "How to create an area", that you want to draw the area on the map, you will find an example right in the map V2 reference doc for the class Circle.
For checking whether the distance between the center of the circle and your point is greater than 10 km I would suggest to use the static method Location.distanceBetween(...) as it avoids unnecessary object creations.
See also here (at the very end of the answer) for a code example in case the area is a polygon rather than a circle.
Related
I am trying my hands on locationtech JTS library. I wanted to find any built methods from JTS that can help me get a new coordinate given that I have following data with me:
Originating Point
Distance to the new coordinate
Bearing angle direction for finding the new coordinate
Also are there any resources apart from Javadocs of JTS library for easier comprehension?
To do that you simply set the start point, distance and direction in the GeodeticCalculator.
DefaultGeographicCRS crs = DefaultGeographicCRS.WGS84;
GeodeticCalculator calc = new GeodeticCalculator(crs);
GeometryFactory geomFactory = new GeometryFactory();
Point point = geomFactory.createPoint(new Coordinate(0.0, 50.0));
calc.setStartingGeographicPoint(point.getX(), point.getY());
// azimuth in degrees -180 - 180
double azimuth = 90.0;
// distance in metres
double distance = 50;
calc.setDirection(azimuth, distance);
Point2D p = calc.getDestinationGeographicPoint();
System.out.println(p);
So i have a point (x,y,z) and a vector (x1,y1,z1) and i want to rotate the point around the vector in a 3D space. From what i read I should be able to do so using quaternions like this:
(0,new_x,new_y,new_z) = K^-1 * I * K
where K = (cos(fi/2), sin(fi/2)*(x1,y1,z1)) (where (x1,y1,z1) is a normalized vector)
I = (0,(x,y,z))
K^-1 = (cos(fi/2), -sin(fi/2)*(x1,y1,z1))
I implemented it like this:
Point3D n = new Point3D(x1,y1,z1);
n=n.normalize();
double a=Math.cos(Math.toRadians(45)); //fi is 90
double b= Math.sin(Math.toRadians(45));
double k_a = a;
double k_b = b*n.getX();
double k_c=b*n.getY();
double k_d = b*n.getZ(); //K points
double k_a2=k_a; //K^-1 points
double k_b2=-k_b;
double k_c2 = -k_c;
double k_d2= -k_d;
//I*K
double a_m = -((x*k_b)+(y*k_c)+(z*k_d));
double b_m= k_a*x+y*k_d+0*k_b-z*k_c;
double c_m = k_a*y+0*k_c+k_b*z-x*k_d;
double d_m = k_a*z+0*k_d+x*k_c-y*k_b;
//K^-1 * what we got above aka the final coordinates
double a_f = k_a2*a_m -b_m*k_b2-c_m*k_c2-d_m*k_d2; //should and is 0
double x_f= k_a2*b_m+a_m*k_b2+k_c2*d_m-k_d2*c_m;
double y_f = k_a2*c_m+a_m*k_c2+k_b2*d_m-k_d2*b_m;
double z_f = k_a2*d_m+a_m*k_d2+k_b2*c_m-k_c2*b_m;
The problem is, that when i use the above code for a animation (rotating a sphere around a vector), instead of a circle i get a spiral, where the sphere quickly ends up in the same place as the vector:
The move it self is done with a button click for now like this:
btn2.setOnAction(new EventHandler() {
#Override
public void handle(ActionEvent e) {
Point3D n = calc(x,y,z,x1,y1,z1); //a call to the method calculating K^-1*I*K shown above
Sphere sphere= new Sphere(10); //I know, drawing a new one everytime is a waste, but i wanted to be sure the translate wasnt at fault since im new at javaFX
sphere.setMaterial(new PhongMaterial(Color.CORAL));
sphere.setTranslateX(n.getX());
sphere.setTranslateY(n.getY());
sphere.setTranslateZ(n.getZ());
x=n.getX();
y=n.getY();
z=n.getZ();
content.group.getChildren().remove(0);
content.group.getChildren().add(0, sphere);
}
});
I think the problem is in the calculation of the new coordinates, after a bit they end up somewhere on the vector, but after rechecking the math more times than i can count, im officially lost. Can anyone tell me what i am missing or where i went wrong?
Oh nevermind, it was an calculation mistake afterall (though i swear i checked it over a thousand times..)
instead of:
double y_f = k_a2*c_m+a_m*k_c2+k_b2*d_m-k_d2*b_m;
its supposed to be:
double y_f = k_a2*c_m+a_m*k_c2-k_b2*d_m+k_d2*b_m;
I am working on an Android app and I have latitude and longitude of a geographic point and I would like to get coordinates of the place located from X meters (North) and Y meters (West). GeoPoint does not implement this kind of functionality so I have to find a way to do it by myself...
I made some searches but I did not find anything interesting, do you have any idea how to proceed?
Tricky, because the distance between two whole longitudes depends on the latitude, and the distance also depends on the altitude...
To make things simple, I'd try and guess the longitude and latitude, and check the distance between the guess and the origin point. This is easier because getting the distance between two points has already been done.
Start with one axis, and do a kind of binary search until you find the location X meters to the north. Then do the same for the other axis.
With the following method you will get the latitude and longitude to add to the original location to get to the final one. Have in mind that this only works over relatively small distances, as it is ignoring the earth curvature.
private static final float GAP_LAT_LON = 0.00005f; //aprox 5 meters
private float results[] = new float[1];
private PointF getGaps(Location initial, float distanceX, float distanceY, PointF gaps){
Location.distanceBetween(initial.getLatitude(), initial.getLongitude(), initial.getLatitude(), initial.getLongitude() + GAP_LAT_LON, results);
double factorX = GAP_LAT_LON / results[0];
Location.distanceBetween(initial.getLatitude(), initial.getLongitude(), initial.getLatitude() + GAP_LAT_LON, initial.getLongitude(), results);
double factorY = GAP_LAT_LON / results[0];
if(gaps == null)
gaps = new PointF();
gaps.set((float)(distanceX * factorX), (float)(distanceY * factorY));
return gaps;
}
//to use
private void teste(){
PointF gaps = null;
Location initial = new Location("");
initial.setLatitude(23.5);
initial.setLongitude(13.2);
//100 meters West/East and 300 meters North/South
getGaps(initial, 100, 300, gaps);
//gaps.x returns x offset to add/subtract to initial latitude
//gaps.y returns y offset to add/subtract to initial longitude
}
good luck
I'm coding a flocking algorithm in Java but I'm stuck at a certain point (using the Ardor3D libraries, in a 2D plane).
Basically, I need to find the angle difference to add to the current rotation. If you can only get the way it should be pointing with polar coordinates with 0 degs at north and not the difference, not to worry -- I have a method which returns the angle difference taking into account the wraparound on the angle and negative angles.
At the moment, I have the following code, which clearly wouldn't work since the algorithm has no reference to the initial rotation:
long tpf = currUpdateTimeMS - lastUpdateTimeMS;
Vector2 pos = new Vector2();
rt.getPosition(pos);
double rot = pos.angleBetween(app.getAvgBoidPos(new Vector2()).normalizeLocal());
rt.setRotation(rot);
pos.addLocal(
Math.cos((rot - MathUtils.HALF_PI)) * (tpf / 10f),
Math.sin((rot - MathUtils.HALF_PI)) * (tpf / 10f)
);
rt.setPosition(pos);
super.updateLogic();
Updated code (not working, from first answer):
long tpf = currUpdateTimeMS - lastUpdateTimeMS;
//rt.setRotation(rt.getRotation() + ((tpf / (ROT_SPEED / 2f)) % 360));
Vector2 avgpos = app.getAvgBoidPos(new Vector2());
Vector2 pos = rt.getPosition(new Vector2());
avgpos.subtractLocal(pos);
double angleRads = rt.getRotation() * FastMath.DEG_TO_RAD;
double rot = MathUtils.acos((
(avgpos.getX() * MathUtils.sin(angleRads)
) +
(avgpos.getY() * MathUtils.cos(angleRads)
)) / ((Math.pow(avgpos.getX(), 2) + Math.pow(avgpos.getY(), 2)) * 0.5));
double adegdiff = rot * FastMath.RAD_TO_DEG;
rt.setRotation(rt.getRotation() - adegdiff);
double newrot = rt.getRotation();
pos.addLocal(
Math.cos((newrot - MathUtils.HALF_PI)) * (tpf / 10f),
Math.sin((newrot - MathUtils.HALF_PI)) * (tpf / 10f)
);
rt.setPosition(pos);
super.updateLogic();
Another modification based on the other answer:
long tpf = currUpdateTimeMS - lastUpdateTimeMS;
//rt.setRotation(rt.getRotation() + ((tpf / (ROT_SPEED / 2f)) % 360));
Vector2 avgpos = app.getAvgBoidPos(new Vector2());
Vector2 pos = rt.getPosition(new Vector2());
avgpos.subtractLocal(pos);
double rot = pos.angleBetween(
app.getAvgBoidPos(new Vector2()).normalizeLocal()
) - (rt.getRotation() * MathUtils.DEG_TO_RAD);
rt.setRotation(rt.getRotation() - (rot * MathUtils.RAD_TO_DEG));
double newrot = rt.getRotation();
pos.addLocal(
Math.cos((newrot - MathUtils.HALF_PI)) * (tpf / 10f),
Math.sin((newrot - MathUtils.HALF_PI)) * (tpf / 10f)
);
rt.setPosition(pos);
super.updateLogic();
I'm not really too good at Maths problems, so code would be helpful rather than formulas :)
Inputs
Current position of entity
Current rotation of entity (polar-oriented) in degrees
Output
Degrees or radians to add or subtract to current rotation
... or degrees or radians expressed as polar-oriented angle
Thanks in advance if you can help :)
Chris
You can use the dot product to determine the cosine of the angle (in radians) between the current orientation and the point you want to face. Assume the agent doing the viewing is locate at the origin and oriented to face some direction given by the angle θ relative to the Y-Axis (i.e. 0 degrees is "up" or "north"). You want to find the angular difference θ' between that direction and facing a point (x, y). That is given by:
θ' = cos-1[(x*sin(θ) + y*cos(θ)) / sqrt(x2 + y2)]
Subtracting θ' from θ will orient the agent towards the target.
If the agent is not at the origin, simply subtract the position of the agent from the object to view to bring it into the form above.
Slightly off topic, but you might find the particle swarm and wander code in our effects package (ardor3d-effects) interesting as well.
They can be found in the ardor svn, or here:
http://ardorlabs.trac.cvsdude.com/Ardor3Dv1/browser/trunk/ardor3d-effects/src/main/java/com/ardor3d/extension/effect/particle/
heres an implementation on how to find the angle beetween two vectors with a common origin. this has been hacked together based on the algorithm described there:
http://www.wikihow.com/Find-the-Angle-Between-Two-Vectors
public class DeltaDoodle {
private double delta(ColumnVector v1,ColumnVector v2) throws Exception{
double sp=scalarProduct(v1,v2);
double magV1=magnitude(v1);
double magV2=magnitude(v2);
return Math.acos(sp/(magV1*magV2)) * (180/Math.PI);
}
private double scalarProduct(ColumnVector a, ColumnVector b) {
return (a.x*b.x) + (a.y*b.y);
}
private double magnitude(ColumnVector a){
return Math.sqrt((a.x*a.x) + (a.y*a.y));
}
public static void main(String[] args) {
DeltaDoodle v=new DeltaDoodle();
try {
System.out.println("angle: " + v.delta(new ColumnVector(5, 5), new ColumnVector(1,1)));
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class ColumnVector {
public final double x, y;
public ColumnVector(double x1, double x2) {
this.x = x1;
this.y = x2;
}
}
hope that helps...
If I understand these functions correctly, this might just work:
Vector2 pos = new Vector2();
rt.getPosition(pos);
double rot = pos.angleBetween(app.getAvgBoidPos(new Vector2()).normalizeLocal()) - rt.getRotation();
P.S. Forgot to mention: this rot is intended to be the angle difference. Rotate the entity by this much and it should be pointing toward the target.
EDIT:
Thanks, the code does help (I had misconstrued angleBetween). Let me try again:
Here is the vector from the entity to the point (pardon me if I get the syntax wrong, I don't know java):
Vector2 pos = new Vector2();
rt.getPosition(pos);
Vector2 direction = app.getAvgBoidPos(new Vector2());
direction.subtractLocal(pos);
Now we normalize it to get a unit vector pointing toward the point, and take the angle difference:
double rot = rt.getRotation().angleBetween(direction.normalizeLocal())
hi I have image of my house.Top view image.I want to have latitude lotitude info displayed when i click on the image.
I do have latitude longitude value for 1 left top part of image.
Also how to maintain latitude longitude values while zooming in out of the image.
Lat/lon is a geodesic coordinate system (WGS84), which means it is curved coordinates going around the earth - an image is flat, which means typically you can't easily go directly between the two. However it may be the case that an image of your house is so small area, that the calculation error will be small enough to be negligible (depending on what you need it for).
To do what you want to do, you need to find a "degrees per pixel" value which means you need to know the lat/lon for both top/left and bottom right of your image. If you have that it's simple. This assumes you're in the northern hemisphere:
var degreesPerPixelX = bottomX - topX / imageWidth;
var degreesPerPixelY = bottomY - topY / imageHeight;
And an event handler (the getEventOffsetFromImageXXX are not shown).
function onClick (evt) {
var x = getEventOffsetFromImageLeft(evt);
var y = getEventOffsetFromImageTop(evt);
var clickedLon = topX + x * degreesPerPixelX;
var clickedLat = bottomY + y * degreesPerPixelY;
}
The zoom level will affect the top/left bottom/right lon/lat so the calculations need to adjust accordingly.
When Google Maps calculate x/y to lon/lat they internally ALWAYS first convert the lon/lat to the coordinate system Spherical Mercator (EPSG:900913), do the operations in that system and then convert back. However Spherical Mercator has fixed zoom levels, which is probably not right for you. Nevertheless, this is a very worthwhile read.
http://www.maptiler.org/google-maps-coordinates-tile-bounds-projection/
N.b. degreesPerPixel is called resolution in google talk and the unit is meters per pixel. Meter is the unit in Spherical Mercator, which roughly translates to a meter at the equator, but is far from a meter the further north/south you get.
Anyone how abt this code snippet
function longToX(longitudeDegrees)
{
var longitude=longitudeDegrees-baselong;
longitude =degreesToRadians(longitude);
return (radius * longitude);
}
function latToY(latitudeDegrees)
{
var latitude=latitudeDegrees-baselat;
latitude =degreesToRadians(latitude);
var newy = radius/2.0 *
Math.log( (1.0 + Math.sin(latitude)) /
(1.0 - Math.sin(latitude)) );
return newy;
}
function xToLong(xx)
{
var longRadians = xx/radius;
var longDegrees = radiansToDegrees(longRadians);
var rotations = Math.floor((longDegrees + 180)/360)
var longitude = longDegrees - (rotations * 360)
return longitude+baselong;
}
function yToLat(yo)
{
var latitude = (Math.PI/2) - (2 * Math.atan(Math.exp(-1.0 * yo /this.radius)));
return radiansToDegrees(latitude)+baselat;
}