I am plotting a route using the osmdroid bonuspack. The start and end coordinates of this route are:-
origin - 52.24896,0.71795
destination - 54.27916,-1.9732
The relevant part of my code is:-
BoundingBox b = getBoundingBox(origin,destination);
map.setMinZoomLevel(7d); // <<==== Needed to initialise zoom level
map.zoomToBoundingBox(b,false);
map.invalidate();
and
private BoundingBox getBoundingBox(GeoPoint start, GeoPoint end) {
double north;
double south;
double east;
double west;
if(start.getLatitude() > end.getLatitude()) {
north = start.getLatitude();
south = end.getLatitude();
} else {
north = end.getLatitude();
south = start.getLatitude();
}
if(start.getLongitude() > end.getLongitude()) {
east = start.getLongitude();
west = end.getLongitude();
} else {
east = end.getLongitude();
west = start.getLongitude();
}
return new BoundingBox(north, east, south, west);
}
The map tiles I'm using are zoom levels 7-13.
Without the 'setMinZoomLevel' statement the origin/destination markers are displayed in the top left corner of the screen at a zoom level that can best be described as deep space. If I include 'setMinZoomLevel' then the map is displayed at that level and doesn't zoom to fit the boundingbox (which should be at level 8). I have tried a much smaller route with exactly the same end result.
What am I doing wrong?
It transpires that a map needs to already be being displayed, presumably so that the screen dimensions have been recorded. The answer, therefore, is firstly to set a zoom level using MapController as part of the onCreate process and then to invoke the zoomToBoundingBox within MapView.OnFirstLayoutListener. The code I used was:-
map.addOnFirstLayoutListener(new MapView.OnFirstLayoutListener() {
public void onFirstLayout(View v, int left, int top, int right, int bottom) {
BoundingBox b = getBoundingBox(origin,destination);
map.zoomToBoundingBox(b,false,100);
map.invalidate();
}
});
Related
New to GeoTools and GIS and I am trying to calculate distance between Mumbai and Durban using GeoTools library. I am getting close to accurate results for small distances but when i go for bigger ones,the calculation is way too offcourse by 2000 km, i dont completely understand the CRS system .Below is my Code to calculate the distance between Mumbai and Durban
Coordinate source = new Coordinate(19.0760, 72.8777); ///Mumbai Lat Long
Coordinate destination1 = new Coordinate(-29.883333, 31.049999); //Durban Lat Long
GeometryFactory geometryFactory = new GeometryFactory();
Geometry point1 = geometryFactory.createPoint(source);
Geometry point2 = geometryFactory.createPoint(destination1);
CoordinateReferenceSystem auto = auto = CRS.decode("AUTO:42001,13.45,52.3");
MathTransform transform = CRS.findMathTransform(DefaultGeographicCRS.WGS84, auto);
Geometry g3 = JTS.transform(point1, transform);
Geometry g4 = JTS.transform(point2, transform);
double distance = g3.distance(g4);
This is what happens when you copy code blindly from stackexchange questions without reading the question it was based on which explains why.
All the times I've answered that question (and posted code like that) the questioner is trying to use lat/lon coordinates in degrees to measure a short distance in metres. The trick shown in your question creates an automatic UTM projection centred on the position specified after the "AUTO:42001," bit (in your case 52N 13E) - this needs to be the centre of the area you are interested in, so in your case those values are probably wrong anyway.
But you aren't interested in a small region Mumbai to Durban is a significant way around the Earth so you need to allow for the curvature of the Earth's surface. Also you aren't trying to do something difficult for which JTS is the only source of process (e.g buffering). In this case you should use the GeodeticCalculator which takes the shape of the Earth into account using the library from C. F. F. Karney, Algorithms for geodesics, J. Geodesy 87, 43–55 (2013).
Anyway enough explanation that no one will read in the future, here's the code:
public static void main(String[] args) {
DefaultGeographicCRS crs = DefaultGeographicCRS.WGS84;
if (args.length != 4) {
System.err.println("Need 4 numbers lat_1 lon_1 lat_2 lon_2");
return;
}
GeometryFactory geomFactory = new GeometryFactory();
Point[] points = new Point[2];
for (int i = 0, k = 0; i < 2; i++, k += 2) {
double x = Double.valueOf(args[k]);
double y = Double.valueOf(args[k + 1]);
if (CRS.getAxisOrder(crs).equals(AxisOrder.NORTH_EAST)) {
System.out.println("working with a lat/lon crs");
points[i] = geomFactory.createPoint(new Coordinate(x, y));
} else {
System.out.println("working with a lon/lat crs");
points[i] = geomFactory.createPoint(new Coordinate(y, x));
}
}
double distance = 0.0;
GeodeticCalculator calc = new GeodeticCalculator(crs);
calc.setStartingGeographicPoint(points[0].getX(), points[0].getY());
calc.setDestinationGeographicPoint(points[1].getX(), points[1].getY());
distance = calc.getOrthodromicDistance();
double bearing = calc.getAzimuth();
Quantity<Length> dist = Quantities.getQuantity(distance, SI.METRE);
System.out.println(dist.to(MetricPrefix.KILO(SI.METRE)).getValue() + " Km");
System.out.println(dist.to(USCustomary.MILE).getValue() + " miles");
System.out.println("Bearing " + bearing + " degrees");
}
Giving:
working with a lon/lat crs
POINT (72.8777 19.076)
POINT (31.049999 -29.883333)
7032.866960793305 Km
4370.020928274692 miles
Bearing -139.53428618565218 degrees
I want to display a hurricane (big isosurface object) in Cesium. For this I converted an OBJ file with longitude, latitude, altitude columns for each vertex of the isosurface representing the hurricane, in a new OBJ file reprojected in ECEF (Earth Centered) projection.So the final OBJ file contains now X,Y,Z for each vertex instead of longitude, latitude, altitude. After final reformat by obj2gltf, I try to display the GLTF "hurricane" file in Cesium.JS using the code below:
console.log('loading hurricane.gltf';
var mymodel = viewer.scene.primitives.add(Cesium.Model.fromGltf({
url : 'data/hurricane.gltf',
modelMatrix : Cesium.Matrix4.IDENTITY,
asynchronous: false
}));
I can see my hurricane on the earth, but not at the good position. I suspect a problem of matrix. IDENTITY matrix seems not to be the good one. I could try to make a new matrix but I can't find enough informations about the axes orientation used by Cesium.
I verified the X,Y,Z ECEF coordinates, they are good. Does anyone already meet this problem ?
If your glTF model origin is at the center of the hurricane, you can place it using a Cesium Entity, something like this:
// Longitude degrees, Latitude degrees, height in meters
var position = Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706, height);
var heading = Cesium.Math.toRadians(0);
var pitch = 0;
var roll = 0;
var hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
var orientation = Cesium.Transforms.headingPitchRollQuaternion(position, hpr);
var entity = viewer.entities.add({
name : 'Hurricane',
position : position,
orientation : orientation,
model : {
uri : 'data/hurricane.gltf'
}
});
viewer.trackedEntity = entity;
There are more complete working demos of this on Sandcastle.
But, if your hurricane is visible on the surface of the Earth using the identity matrix, that likely means that the origin of that model is nowhere near the center of the hurricane. You may need to edit the glTF file, to make sure that the model is centered on its own origin, and does not have some fixed Earth location pre-baked into the model's internal transformations.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I am coming up or am looking for an equation to this trivial problem:
Well it's more about knowing the direction in which the user is going based on the users geo location.
As you can see below the User's first coordinates are in point x after a minute or two the user's coordinates changed and is now at point y
Given the User's coordinates x and y , the Intersection point A and Point B
how do I come up with a formula that would tell me if the user is in the right lane (going from point B to point A)
or is in the left lane (going from point A to point B).
Assuming this is just coordinate based, and does NOT need to take into consideration the road or path the points are on, use the dot product. Create segments from points and dot product of two segments is positive if segments are aligned (point is same direction with less than 90 degrees) and negative if segments point in opposite directions.
If problem needs to consider the road or path, then the below will not work, because road/path may at times curve back and be moving away from destination, so correct direction on the road/path would temporarily be increasing distance to destination (as the crow flies). As your question is worded it SOUNDS like you want to be able to tell, from a single user position X and Y values which lane of a defined road they are in. If you think about it, that is simply not possible without knowing the exact geometry of the road/path itself. If it is curved at all, it becomes impossible to determine. Think about it. For ANY given position on the ground, you could bend the road one way or the other to cause that spot to be in either lane...
But with TWO positions, that represent movement in time, and the assumption that they are moving forward in whatever lane they are in, you CAN determine whether that motion is more towards Point A or towards Point B.
Technically, dot product of two vectors A and B
A dot B = |A| x |B| x Cos(Angle between them))
So, and AGAIN, this is assuming you don't need to take into consideration the shape or curvature of the road, you just make two directed segments, one from B to A, and another from one user position to a subsequent user position (representing his/her motion during some finite time interval), and take the dot product of these two segments. If it's positive, he's moving towards A, if negative, hes moving towards B.
(this code is simplified)
public struct Point
{
public double X { get; set; }
public double Y { get; set; }
private Point(double xValue, double yValue)
{ X = xValue; Y = yValue; }
public static Point Make(double x, double y)
{ return new Point(x, y); }
}
public class Segment
{
public Point StartPoint { get; set; }
public Point EndPoint { get; set; }
#region ctor / factories
protected Segment(Point startPoint, Point endPoint)
: base(startPoint, (endPoint.Y - startPoint.Y) /
(endPoint.X - startPoint.X))
{
StartPoint = startPoint;
EndPoint = endPoint;
}
public static new Segment Make(Point startPoint, Point endPoint)
{
if (startPoint == endPoint)
throw new Exception(
"You must use two different points to define a segment.");
return new Segment(startPoint, endPoint);
}
public static new Segment Make(double ax, double ay, double px, double py)
{ return Make(Point.Make(ax, ay), Point.Make(px, py)); }
public static Segment NullSegment { get { return new Segment(); } }
#endregion ctor / factories
public double Length
{
get
{
return Math.Sqrt(
Math.Pow(EndPoint.Y - StartPoint.Y, 2) +
Math.Pow(EndPoint.X - StartPoint.X, 2));
}
}
public double DotProduct(Segment seg, bool normalize = false)
{
double
dAx = EndPoint.X - StartPoint.X,
dAy = EndPoint.Y - StartPoint.Y,
dBx = seg.EndPoint.X - seg.StartPoint.X,
dBy = seg.EndPoint.Y - seg.StartPoint.Y;
var dP = dAx * dBx + dAy * dBy;
return normalize? dP / Length / seg.Length : dP;
}
}
Do anybody know how the google map bound calculation can be done without using any UI element and Javascript.
I have set of points and different zoom level. I can probably add the screen size and I need to calculate the bounds for provided coordinate and zoom level. I am trying to do this in the plain C# code.
Please help.
as for calculating bounds - you can do it easily by walking array of your coordinates and extend bounds rectangle if point falls out. First coord is a start. I don't familiar with C# but there is the algo using pseudocode:
points = Array of coord(lat, lng)
bounds = object {
top: null
left: null
right: null
bottom: null
function extend(coord: (lat, lng))
{
if (this.top == null) // empty
{
this.top = coord.lat; this.bottom = coord.lat;
this.left = coord.lng; this.right = coord.lng;
}
else
{
if (coord.lng < this.left) this.left = coord.lng;
if (coord.lat < this.bottom) this.bottom = coord.lat;
if (coord.lng > this.right) this.right = coord.lng;
if (coord.lat > this.top) this.top = coord.lat;
}
}
}
But of course much simplier way is to use already written google functionality.
Zoom level can be calculated somehow from the size of bounding box (for example you can find a table with rates in km or miles per pixel, or approximate width or map), but most comfortable way is map.fitBounds(bounds)
Ok pretty self explanatory. I'm using google maps and I'm trying to find out if a lat,long point is within a circle of radius say x (x is chosen by the user).
Bounding box will not work for this. I have already tried using the following code:
distlatLng = new google.maps.LatLng(dist.latlng[0],dist.latlng[1]);
var latLngBounds = circle.getBounds();
if(latLngBounds.contains(distlatLng)){
dropPins(distlatLng,dist.f_addr);
}
This still results in markers being places outside the circle.
I'm guess this is some simple maths requiring the calculation of the curvature or an area but I'm not sure where to begin. Any suggestions?
Unfortunately Pythagoras is no help on a sphere. Thus Stuart Beard's answer is incorrect; longitude differences don't have a fixed ratio to metres but depend on the latitude.
The correct way is to use the formula for great circle distances. A good approximation, assuming a spherical earth, is this (in C++):
/** Find the great-circle distance in metres, assuming a spherical earth, between two lat-long points in degrees. */
inline double GreatCircleDistanceInMeters(double aLong1,double aLat1,double aLong2,double aLat2)
{
aLong1 *= KDegreesToRadiansDouble;
aLat1 *= KDegreesToRadiansDouble;
aLong2 *= KDegreesToRadiansDouble;
aLat2 *= KDegreesToRadiansDouble;
double cos_angle = sin(aLat1) * sin(aLat2) + cos(aLat1) * cos(aLat2) * cos(aLong2 - aLong1);
/*
Inaccurate trig functions can cause cos_angle to be a tiny amount
greater than 1 if the two positions are very close. That in turn causes
acos to give a domain error and return the special floating point value
-1.#IND000000000000, meaning 'indefinite'. Observed on VS2008 on 64-bit Windows.
*/
if (cos_angle >= 1)
return 0;
double angle = acos(cos_angle);
return angle * KEquatorialRadiusInMetres;
}
where
const double KPiDouble = 3.141592654;
const double KDegreesToRadiansDouble = KPiDouble / 180.0;
and
/**
A constant to convert radians to metres for the Mercator and other projections.
It is the semi-major axis (equatorial radius) used by the WGS 84 datum (see http://en.wikipedia.org/wiki/WGS84).
*/
const int32 KEquatorialRadiusInMetres = 6378137;
Use Google Maps API geometry library to calculate distance between circle's center and your marker, and then compare it with your radius.
var pointIsInsideCircle = google.maps.geometry.spherical.computeDistanceBetween(circle.getCenter(), point) <= circle.getRadius();
It's very simple. You just have to calculate distance between centre and given point and compare it to radius. You can Get Help to calculate distance between two lat lang from here
The following code works for me: my marker cannot be dragged outside the circle, instead it just hangs at its edge (in any direction) and the last valid position is preserved.
The function is the eventhandler for the markers 'drag' event.
_markerDragged : function() {
var latLng = this.marker.getPosition();
var center = this.circle.getCenter();
var radius = this.circle.getRadius();
if (this.circleBounds.contains(latLng) &&
(google.maps.geometry.spherical.computeDistanceBetween(latLng, center) <= radius)) {
this.lastMarkerPos = latLng;
this._geocodePosition(latLng);
} else {
// Prevent dragging marker outside circle
// see (comments of) http://unserkaiser.com/code/google-maps-marker-check-if-in-circle/
// see http://www.mvjantzen.com/blog/?p=3190 and source code of http://mvjantzen.com/cabi/trips4q2012.html
this.marker.setPosition(this.lastMarkerPos);
}
},
Thanks to http://unserkaiser.com/code/google-maps-marker-check-if-in-circle/
and http://www.mvjantzen.com/blog/?p=3190 .
I've been a bit silly really. Thinking about it we can use Pythagorus' theorem.
We have a maximum distance away from a point (X miles), and two latitudes and two longitudes. If we form a triangle using these then we can solve for the distance from the point.
So say we know point1 with coordinates lat1,lng1 is the center of the circle and point2 with coordinates lat2,lng2 is the point we are trying to decide is in the circle or not.
We form a right angled triangle using a point determined by point1 and point2. This, point3 would have coordinates lat1,lng2 or lat2,lng1 (it doesn't matter which). We then calculate the differences (or if you prefer) distances - latDiff = lat2-lat1 and lngDiff = lng2-lng1
we then calculate the distance from the center using Pythagorus - dist=sqrt(lngDiff^2+latDiff^2).
We have to translate everything into meters so that it works correctly with google maps so miles are multiplied by 1609 (approx) and degrees of latitude/longitude by 111000 (approx). This isn't exactly accurate but it does an adequate job.
Hope that all makes sense.