I'm using the computeOffset() from the SpericalUtil in the google maps android library. The computeOffset takes the parameters:
public static LatLng computeOffset(LatLng from, double distance, double heading)
with the original coordinates of the first two markers I can use the computeOffset to generate another line after inputing the distance and the heading. My goal is to make parallel lines at a certain distance apart. But as you can see below it looks pretty good when the lines are nearly north and south, but when you go towards east and west it looks to me like the distance between the two lines isn't the same value. The end points appear to be the right distance but offset. How can I make it so all the lines look like the first image no matter what direction?
public void onMarkerDragEnd(Marker marker) {
showDistance();
LatLng markerCPosition = SphericalUtil.computeOffset(mMarkerA.getPosition(), 50, 90);
mMarkerC = getMap().addMarker(new MarkerOptions().position(markerCPosition).draggable(true).visible(false));
LatLng markerDPosition = SphericalUtil.computeOffset(mMarkerB.getPosition(), 50, 90);
mMarkerD = getMap().addMarker(new MarkerOptions().position(markerDPosition).draggable(true).visible(false));
updatePolyline();
}
At the moment you're just shifting the points sideways using a constant angle (90 degrees). If I understand you correctly and you want both lines parallel to each other separated by some distance you need to take into account the heading of the original A-B line like so:
double heading = SphericalUtil.computeHeading(posA, posB);
LatLng markerCPosition = SphericalUtil.computeOffset(posA, 50, heading + 90);
LatLng markerDPosition = SphericalUtil.computeOffset(posB, 50, heading + 90);
Related
I am working coordinates system as shown below:
x and y are in meters. I am interested in only positive x,y. I want to convert (x,y) to (lat,lon) and vise versa.
I thought it is simple and I dont see a problem with my solutions below. But I am not getting very correct results.
My Solution:
As we see in the image below, I considered the Latitude and Longitude as angles of 2 circles:
1. (x,y) to (lat,lon)
I applied the Arc Length formula (here), shown below, on both; x and y
Hence, my functions are:
private static double calculateLat(float x) {
int earthRadius = 6371000;
return REF_LOC.getLatitude() + x*360/(2*PI*earthRadius);
}
private static double calculateLong(float y) {
int earthRadius = 6371000;
return REF_LOC.getLongitude() + y*360/(2*PI*earthRadius);
}
REF_LOC is the reference Geo Location for which (x,y) are (0,0). It can be any point on earth.
2. (lat,lon) to (x,y)
For this I am simply using this:
int calculateX(double longitude){
Location.distanceBetween(REF_LOC.getLatitude(), REF_LOC.getLongitude(),
REF_LOC.getLatitude(), lonDeg, results);
return results[0];
}
int calculateY(double latitude){
Location.distanceBetween(REF_LOC.getLatitude(), REF_LOC.getLongitude(),
latDeg, REF_LOC.getLongitude(), results);
return results[0];
}
But I am getting inconsistent results. First I use solution 1 and convert some value (x,y) to (lat,long). But when I use the same (lat,long) back to (x,y) using solution 2, I get about 2 meters difference in x and 10 meters in y. Can anyone help me identify the problem please?
Alluding to my comment on spherical vs elliptical calculations, another way to look at difference in distance calculations for spherical vs elliptical distance is to use the 2 available utilities:
// For REF_LOC = (70, 20)
// Compute a lat/lng due east of a REF_LOC and compute distance using both
// available methods.
LatLng P = SphericalUtil.computeOffsetOrigin(REF_LOC, 20000, 90.0);
// And then compute a distance
d = SphericalUtil.computeDistanceBetween(REF_LOC, P);
Location.distanceBetween(REF_LOC.latitude, REF_LOC.longitude, P.latitude, P.longitude, results);
// d = 20000.000000000036
// results[0] = 20081.818
// and for a REF_LOC = (0, 20)
// d = 20000.000000000127
// results[0] = 20022.377
What's also interesting is the SphericalUtil.computeOffsetOrigin() produces error
in latitude increasing from equator to pole making it non-symmetrical. Yet the resulting distances are essentially exact.
I'd recommend using SphericalUtil.computeOffsetOrigin to compute the X/Y breaking
it into the latitude and longitude offsets as you are doing.
Finally demonstrating the SphericalUtil solution:
// Start with some arbitrary x/y relative to REF_LOC
double Rx = 125.0;
double Ry = 73.0;
// Compute a lat/lon from REF_LOC to the point
LatLng Rll = new LatLng(SphericalUtil.computeOffsetOrigin(REF_LOC, Ry, 180).latitude,
SphericalUtil.computeOffsetOrigin(REF_LOC, Rx, 270).longitude);
// And recompute the x/y components of the lat/lon
double Rxx = SphericalUtil.computeDistanceBetween(REF_LOC, new LatLng(REF_LOC.latitude, Rll.longitude));
double Ryy = SphericalUtil.computeDistanceBetween(REF_LOC, new LatLng(Rll.latitude, REF_LOC.longitude));
Resulting in:
Rx/Ry = (125.0, 73.0)
Rxx/Ryy = (125.00000004545973, 73.00000000137051)
Acceptable error I assume.
So the parting question is - what does the x/y really represent?
Reference the source for both utilities for more information:
Location
SphericalUtil
What I want to do is calculate a circle's radius by which the user is viewing the map.
I've written the solution so far as follows (which is true):
mMap.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() {
#Override
public void onCameraChange(CameraPosition cameraPosition) {
String TAG = AppController.TAG;
LatLngBounds bounds = mMap.getProjection().getVisibleRegion().latLngBounds;
LatLng target = cameraPosition.target;
LatLng northEast = bounds.northeast;
LatLng southEast = bounds.southwest;
float[] results1 = new float[1];
float[] results2 = new float[1];
Location.distanceBetween(target.latitude, target.longitude, northEast.latitude, northEast.longitude, results1);
Location.distanceBetween(target.latitude, target.longitude, southEast.latitude, southEast.longitude, results2);
double distance = results1[0] > results2[0] ? results1[0] : results2[0];
Log.d(TAG, "onCameraChange:" + results1[0] + " " + results2[0]);
}
});
I'm facing two questions here:
1- First of all why the distane between the center and north east isn't equal to south west?
2- Is there any built in method to achieve the same result?
as you can see from the map above, the horizontal line (latitude) gets shorter the further away you get from the equator.
on the screen, the map is 'distorted' to flatten the curved surface of the earth, with +/- the same amount of longitude and latitude from the center of the view.
so unless you are taking measurements directly at the equator, you will have slight differences in the radius. for small distances, this is negligible.
if accuracy is not important, you can try using the smaller radius (if you want to draw a circle on the view that will not be partially hidden), or use the bigger radius (if you want to do calculations for places within that cicle).
I have a GoogleMap in my project. It's set in zoom level 18. I want to draw a line that is 1 meter in length. I saw and use a code Like this:
googleMap.addCircle(new CircleOptions()
.center(latLng1)
.radius(5)
.fillColor(Color.BLUE));
I gave it's radius in meters. how can I do it with a line?(polyLine doesn't have this options) a line with specific LatLng and specific direction(for example: Heading from north) and specific length?
I can specify direction by sin and cos.. but what can I do for length of the line?
For given point there is only one circle with given radius. But with lines the situation is a bit different. For given point there are infinite number of lines starting from this points and given length. Therefore you can't simple draw such line.
One way to do it is to pick a point on the circle with radius 1 meter and center your point. Here is a good example how to calculate point on a circle with given radius. Than just draw a line between the two points.
UPDATE:
This may help you how to find the LatLng points on the circle LatLng Points on circle on Google Map V2 in Android
To compute line end I use:
SphericalUtil.computeOffset(LatLng,lenght,heading);
To compute width in meters I use this:
public Double calcw(GoogleMap map,int ancho,LatLng p) {
float tilt = map.getCameraPosition().tilt;
CameraPosition old=map.getCameraPosition();
if(tilt!=0){
CameraPosition cameraPosition = new CameraPosition.Builder()
.target(old.target) // Sets the center of the map to Mountain View
.zoom(old.zoom) // Sets the zoom
.bearing(old.bearing) // Sets the orientation of the camera to east
.tilt(0) // Sets the tilt of the camera to 30 degrees
.build();
map.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
}
Point g1 =map.getProjection().toScreenLocation(p);
Point g2=map.getProjection().toScreenLocation(SphericalUtil.computeOffset(p,ancho/10,0));
Double result=(distance(g1,g2));
//Log.e("PROJ1",Double.toString(distance(g1,g2)));
map.moveCamera(CameraUpdateFactory.newCameraPosition(old));
return result;
}
public double distance(Point a, Point b)
{
double dx = a.x - b.x;
double dy = a.y - b.y;
return Math.sqrt(dx * dx + dy * dy);
}
Use polyline to draw line something like below,
private ArrayList<LatLng> mLatlngs ;
PolylineOptions mPolylineOptions = new PolylineOptions();
mPolylineOptions.color(Color.RED);
mPolylineOptions.width(3);
mPolylineOptions.addAll(mLatlngs);
mGoogleMap.addPolyline(mPolylineOptions);
At present I am using circles to display the path of an object of a certain width in meters on a map. This is problematic because at the rate of even 15 mph the circle method would have to be taken every few hundred milliseconds so that the circles overlap so you don't get gaps between the circles. After an hour you end up with countless circles and no memory.
CircleOptions circleOptions = new CircleOptions()
.center(new LatLng(location.getLatitude(), location.getLongitude()));
circleOptions.radius(radi); // In meters
Currently I can't seem to find where the google maps android api v2 supports using a polyline with set radius in meters, but only in pixel width. With varying zoom levels and screen conditions and the projection of the map this sounds rather complicated to basically highlight a path of certain width on the map with a polyline.
Has anyone seen any alternative to using the circle radius method in the api?
Using android-maps-utils this becomes relatively simple:
public static PolygonOptions getPolygonOptions(LatLng point1, LatLng point2, float widthInMeters) {
double heading = SphericalUtil.computeHeading(point1, point2);
double distance = SphericalUtil.computeDistanceBetween(point1, point2);
LatLng corner1 = SphericalUtil.computeOffset(point2, widthInMeters / 2, heading + 90);
LatLng corner2 = SphericalUtil.computeOffset(point2, widthInMeters / 2, heading - 90);
LatLng corner3 = SphericalUtil.computeOffset(corner2, distance, heading + 180);
LatLng corner4 = SphericalUtil.computeOffset(corner3, widthInMeters, heading + 90);
return new PolygonOptions().add(corner1, corner2, corner3, corner4);
}
And then add polygons connecting your points:
map.addPolygon(
getPolygonOptions(point1, point2, 50)
.fillColor(Color.BLACK)
);
map.addPolygon(
getPolygonOptions(point2, point3, 50)
.fillColor(Color.BLACK)
);
I created an android app to draw free shapes over google map v2. The idea of the app is that I combines two apps, one is to draw free shapes and the other is normal google map v2 app.
This link is my last question about this app and it contains the code
The app works well with me but now I have a new problem. My problem is that when I draw a line over a specific location on the map and convert control to map and drag it, I found that the line keep in its place in the view and the map moves under the line and this leads the line to be in another location not the location that I want.
Is there are any way to make the line to be steady in the location I draw in it and when I drag the map the line dragged with its location?
Hope anyone got my mean.
For example if you are drawing line on your mapview using canvas then you need to get x,y points of start and end point.
Then by following code you can change that x,y points into latitude and longitude.
public boolean onTouchEvent(MotionEvent event)
{
int X = (int)event.getX();
int Y = (int)event.getY();
GeoPoint geoPoint = mapView.getProjection().fromPixels(X, Y);
}
Then resgister listener on your mapvierw like this.
map.setOnCameraChangeListener(new OnCameraChangeListener() {
#Override
public void onCameraChange(CameraPosition arg0) {
// Move camera.
Here remove your view from screen and then get lat long of visible region by passing x,y points of 4 regions in `mapView.getProjection().fromPixels(x,y)` and then check if latitude and longitude of your line within range if yes then drawline by following code.
float pisteX;
float pisteY;
Projection projection = this.mapView.getProjection();
Point pt = new Point();
GeoPoint gie = new GeoPoint(latitude,longitude);
Rect rec = mapView.getScreenRect(new Rect());
projection.toPixels(gie, pt);
pisteX = pt.x-rec.left; // car X screen coord
pisteY = pt.y-rec.top; // car Y screen coord
Now draw line between this two (x,y) points.
}
});
Hope I can make you clear and you can understand what I want to say.