I have the following setup of items in real life:
The radar is static, which means it always has the same position. The A-item can move and its position can be whatever. From the radar I can read the x and y coordinates of A in relation to the radar. I have written the following classes to describe the position of each item:
public class Position {
public enum Direction {
EAST, WEST, NORTH, SOUTH
};
public final Direction latitudeDirection, longitudeDirection;
public final float latitude, longitude, altitude;
public Position(Direction latitudeDirection, Direction longitudeDirection,
float latitude, float longitude, float altitude) {
this.latitudeDirection = latitudeDirection;
this.longitudeDirection = longitudeDirection;
this.latitude = latitude;
this.longitude = longitude;
this.altitude = altitude;
}
public Position(float radarX, float radarY) {
// TODO: Implement the question here
this.altitude = Config.RADAR_POSITION.altitude;
}
}
class Config {
// Position of the radar
public static final Position RADAR_POSITION = new Position(
Position.Direction.NORTH, // Latitude direction
Position.Direction.EAST, // Longitude direction
55.0f, // Latitude
13.0f, // Longitude
60.0f); // Altitude
// Facing direction of the radar in degrees. 0° is north, advancing
// clockwise.
public static final float RADAR_FACING_DIRECTION = 10.0f;
}
Now given the geographic coordinates of the radar, the x and y coordinates of A relative to the radar and the facing direction of the radar relative to the North, how can I calculate the absolute geographic coordinates of A?
The curvature of the earth is not an issue since the maximum value of x and/or y cannot be more than a couple hundred meters.
As an example, you can use trigonometric functions to create triangles to find coordinates of A:
In this case, Ax = (y)(cos 10) - (x)(cos 80), and you could work out Ay similarly.
This way, you are never stuck in degrees, you are simply working in meters.
The robust solution is Vishal's comment in the OP, which was posted whilst I was drawing and scanning:
xnew = x * cos(theta) - y * sin(theta);
ynew = x * sin(theta) + y * cos(theta);
In general, you can use the following steps:
transform your radar position (lat, lon, height) into metric earth centered earth fixed xyz-system (ECEF)
You can then use/combine any rotation and translation arguments/matrices, which describe radar rotation and object position, in this metric system
back transform newly acquired xzy coordinates to lat/lon/h
There are many ressources for such transformations, check this, for instance: http://www.gmat.unsw.edu.au/snap/gps/clynch_pdfs/coordcvt.pdf
You can also introduce a scene coordinate system, if needed (ENU). Here is a fairly good overview describing the relation of UTM, ECEF, ENU and geodotic coordinates(Lat/lon/h):
http://www.dirsig.org/docs/new/coordinates.html
If you need sample code for ECEF to/from Geodetic conversion, have a look at the matlab code, http://www.mathworks.de/de/help/map/ref/ecef2geodetic.html,
or use a library like GDAL (http://www.gdal.org/)
I think it should be possible to do it this way: Convert the x and y coordinates to polar coordinates r and theta, (with the radar as the origin). Subtract the radar's rotation, and convert back to cartesian coordinates. Then you just have to convert to latitude and longitude and add the coordinates of the radar.
double r = Math.hypot(radarX, radarY);
double theta = Math.atan2(radarY, radarX);
theta -= Math.toRadians(Config.RADAR_FACING_DIRECTION);
float x = (float) r * Math.cos(theta);
float y = (float) r * Math.sin(theta);
longitude = metersToLongitude(Config.RADAR_POSITION, y) + Config.RADAR_POSITION.longitude;
latitude = metersToLatitude(Config.RADAR_POSITION, x) + Config.RADAR_POSITION.latitude;
I found formulae for the length of a degree of latitude and longitude on Wikipedia. A degree of latitude is the same everywhere but longitude gets smaller near the poles.
static float metersToLatitude(Position near, float meters) {
return meters / 110.6*1000;
}
static float metersToLongitude(Position near, float meters) {
float lat = Math.toRadians(near.latitude);
return meters /
(111132.954 - 559.822 * Math.cos(2*lat) + 1.175 * Math.cos(4*lat));
}
Unfortunately this doesn't seem to work and I can't figure out why.
If you want to express your coordinates in positive degrees east/west/north/south you'll also have to check if they're negative and invert them and the direction in that case.
Does this help for conversion?
http://en.wikipedia.org/wiki/Geodetic_system#From_geodetic_to_ECEF ?
Finally I solved it. The code is attached below. Since Samuel Edwin Ward's answer is the one that inspired me, I will accept his answer.
public Position(float radarX, float radarY) {
// Convert A's position to distance and bearing in relation to the North
double objDistance = (Math.hypot(radarX, radarY) / 6367500 /* Mean earth radius */);
double objBearing = (Math.atan2(radarY, radarX) + Math.toRadians(Config.RADAR_BEARING));
// Convert the Radar's geographic coordinates to radians
double latitudeRadar = Math.toRadians(Config.RADAR_POSITION.latitude);
double longitudeRadar = Math.toRadians(Config.RADAR_POSITION.longitude);
// Calculate A's geographic coordinates in radians
double latitudeObject = Math.asin(Math.sin(latitudeRadar)*Math.cos(objDistance) +
Math.cos(latitudeRadar)*Math.sin(objDistance)*Math.cos(objBearing));
double longitudeObject = longitudeRadar + Math.atan2(Math.sin(objBearing)*Math.sin(objDistance)*Math.cos(latitudeRadar),
Math.cos(objDistance)-Math.sin(latitudeRadar)*Math.sin(latitudeObject));
// Normalize to -180 ... +180 degrees
longitudeObject = (longitudeObject+3*Math.PI) % (2*Math.PI) - Math.PI;
// Set the A's coordinates in degrees
this.latitude = (float) Math.toDegrees(latitudeObject);
this.longitude = (float) Math.toDegrees(longitudeObject);
// Set the rest of the arguments
this.latitudeDirection = Config.RADAR_POSITION.latitudeDirection;
this.longitudeDirection = Config.RADAR_POSITION.longitudeDirection;
this.altitude = Config.RADAR_POSITION.altitude;
}
You rotate all coordinates in the local system of the radar -10° and are then able to just add the radar's x/y coordinates to the A object coordinates.
Related
Im writing a program, that takes 3d coordinates and places them on a 3d globe, projected onto a 2d screen. To turn the coordinates around an axis, i wanted to use the normal of the two points (start- and end- point (of the flight)), to turn it onto the x3 axis and then turn the rest of the points in the same manner, to eventually calculate the points, that i need to animate a point, that goes from point A to point B. the matrix I use to put the points onto the globe is:
public double[] genXYZ(double phi, double theta) {
double[] coords3D = new double[3];
phi = Math.toRadians(phi);
theta = Math.toRadians(theta);
coords3D[0] = Math.cos(theta) * Math.cos(phi);
coords3D[1] = Math.cos(theta) * Math.sin(phi);
coords3D[2] = Math.sin(theta);
return coords3D;
}
everything works just fine. Until I try to calculate the phi and theta angles of the normal (after I calculate the normal correctly).
public double[] getNAngles(double[] ncoords) {
double[] NAngles = new double[2];
NAngles[1] = Math.asin(Math.toRadians(ncoords[2]));
NAngles[0] = Math.acos(ncoords[0] / Math.cos(NAngles[1]));
NAngles[0] = Math.toDegrees(NAngles[0]);
NAngles[1] = Math.toDegrees(NAngles[1]);
System.out.println("N phi: " + NAngles[0]);
System.out.println("N theta: " + NAngles[1]);
return NAngles;
}
Globe
Cyan: start (Greenwich)
Magenta: end (Istanbul)
Black: normal
Pink: what the code calculated, what angles black has.
Thanks in advance!
Remove Math.toRadians call because coords are not angles, they are dimensionless values in range -1..1
NAngles[1] = Math.asin(ncoords[2]);
Also consider using atan2 function for NAngles[0] calculation to exclude sign effects and arccosine angle limit (0..Pi).
NAngles[0] = Math.atan2(ncoords[1], ncoords[0]);
Please take a look at my other question which this was done incorrectly here.
What I need to do
I have an image of a map of my country, I took the piece of the map from Google Maps, so that means I know all of the corner's coordinates in longitude and latitude. My program needs to show up the map, and paint targets on it where each target has its only longitude and latitude, similar to how radar displays targets.
The problem
The problem with my solution is that it's not really using real mathematical formulas to get the X, Y position. It uses simple division and multiple by ratio with minimum and maximum as you can see in my other question.
this is the method:
protected Location getCoordinatesByGlobe(float latitude, float longitude) {
/**
* Work out minimum and maximums, clamp inside map bounds
*/
latitude = Math.max(mapLatitudeMin, Math.min(mapLatitudeMax, latitude));
longitude = Math.max(mapLongitudeMin, Math.min(mapLongitudeMax, longitude));
/**
* We need the distance from 0 or minimum long/lat
*/
float adjLon = longitude - mapLongitudeMin;
float adjLat = latitude - mapLatitudeMin;
float mapLongWidth = mapLongitudeMax - mapLongitudeMin;
float mapLatHeight = mapLatitudeMax - mapLatitudeMin;
float mapWidth = mapImage.getWidth();
float mapHeight = mapImage.getHeight();
float longPixelRatio = mapWidth / mapLongWidth;
float latPixelRatio = mapHeight / mapLatHeight;
int x = Math.round(adjLon * longPixelRatio) - 3;// these are offsets for the target icon that shows.. eedit laterrr #oz
int y = Math.round(adjLat * latPixelRatio) + 3; //
// turn it up
y = (int) (mapHeight - y);
return new Location(x, y);
}
What I have tried
So I was a bit with myself tried to think of something logical, on how can I do this. And I came up with something that doesn't really work exactly:
If we have the corner top-left for example coordinates (Longitude and latitude), and we have the coordinates of the target that we want to display, that means we can do distanceToPoint to know how many kilometers far from the start it is.
After that, we need to know the heading to that point, so we do calculateHeading which gives us the angle to the target point.
So lets call A the starting point (top-left corner)
float aLat = 33.49f;
float aLong = 33.69f;
And our target point we call it b:
float bLat = 32f;
float bLong = 35f;
And then we can calculate the distance from A to B in kilometers:
double km = distanceTopPoint(aLat, aLong, bLat, bLong);
And then we calculate the angle to the point:
double angle = calculateHeading(aLat, aLong, bLat, bLong);
And if we have the km distance and angle, we can know the distance in km for longitude and latitude:
int latDistance = (int) Math.round(km * Math.cos(angle));
int lonDistance = (int) Math.round(km * Math.sin(angle));
So now I probably have the distance from the longitude to the target's longitude and same for latitude. But what can I do with this information?
I tried thinking again, and I figured out that I can know the distance from the left top corner to the right top corner distance in km and same for top left corner to top left bottom corner. And then I can do width / km to get the km per pixel.
But I am really unsure, im sure that I am doing something wrong.
Any ideas?
The Mercator projection is a cylindrical projection, i.e. the generalized coordinates can be calculated as:
a = longitude
b = tan(latitude)
These are unscaled coordinates, i.e. they do not correspond to pixel positions.
Let's say you have an image of w x h pixels that represents the area between (min_long, min_lat) - (max_long, max_lat). These coordinates can be converted to generalized projected coordinates with the above formulas, which yields (min_a, min_b) - (max_a, max_b).
Now you need a linear mapping of the generalized coordinates to pixel positions. This linear mapping can be expressed with four parameters (two scaling parameters and two offset parameters):
x = s_a * a + o_a
y = s_b * b = o_a
Therefore, you need to find the four parameters. You know that the top left corner has pixel coordinates (0, 0) and generalized coordinates (min_a, max_b). Similarly for the bottom right corner. This gives you four constraints and a linear system of equations:
0 = s_a * min_a + o_a
0 = s_b * max_b + o_b
w = s_a * max_a + o_a
h = s_b * min_b + o_b
The solution of this system is:
s_a = w / (max_a - min_a)
o_a = -w * min_a / (max_a - min_a)
s_b = -h / (max_b - min_b)
o_b = h * max_b / (max_b - min_b)
And this is it. If you want the pixel coordinates for some arbitrary point `(long, lat), then do the following:
Calculate the generalized coordinates a and b (be careful to use radians when calculating the tangens).
Use the linear map to convert a and b to pixel coordinates x and y with the pre-calculated parameters.
Inversion
To get latitude and longitude from pixel coordinates, do the following:
Calculate the generalized coordinates:
a = (x - o_a) / s_a
b = (x - o_b) / s_b
Calculate the geo-coordinates:
longitude = a
latitude = arc tan (b)
Again, be careful about radians/degrees.
I am need a Java function that will generate a bounding box (rectangle) around a buffer. The buffer is defined by the center point (WGS84 coordinate) and the radius (in meters).
Getting a bounding box for a buffer in JTS seems to be quite simple:
Point center = ....
Geometry boundingBox = center.buffer(...).getEnvelope();
This however is pure planar geometry. Is there a way to do this using a coordinate reference system with the distance given in meters?
Optimally with Geotools but other Java solutions will also work...
Although you have approached it in another way, I have another solution for that. The results will be way more precise than with your proposed solution.
GeometryFactory GEOMETRY_FACTORY = JTSFactoryFinder.getGeometryFactory();
// Remember, order is (longitude, latitude)
Coordinate center = Coordinate(2.29443, 48.85816);
Point point = GEOMETRY_FACTORY.createPoint(center);
// Buffer 50KM around the point, then get the envelope
Envelope envelopeInternal = buffer(point, 50000).getEnvelopeInternal();
// Then you can play with the envelope, e.g.,
double minX = envelopeInternal.getMinX();
double maxX = envelopeInternal.getMaxX();
// The buffer using distanceInMeters
private Geometry buffer(Geometry geometry, double distanceInMeters) throws FactoryException, TransformException {
String code = "AUTO:42001," + geometry.getCentroid().getCoordinate().x + "," + geometry.getCentroid().getCoordinate().y;
CoordinateReferenceSystem auto = CRS.decode(code);
MathTransform toTransform = CRS.findMathTransform(DefaultGeographicCRS.WGS84, auto);
MathTransform fromTransform = CRS.findMathTransform(auto, DefaultGeographicCRS.WGS84);
Geometry pGeom = JTS.transform(geometry, toTransform);
Geometry pBufferedGeom = pGeom.buffer(distanceInMeters);
return JTS.transform(pBufferedGeom, fromTransform);
}
And here is the map with the result, buffer in red, envelope in black.
I ended up using a GeodeticCalculator to manually find the corners of the box. Frankly the results aren't very precise, but that's the best solution I found till now:
GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory();
CoordinateReferenceSystem wgs84 = DefaultGeographicCRS.WGS84;
GeodeticCalculator geodeticCalculator = new GeodeticCalculator(wgs84);
geodeticCalculator.setStartingGeographicPoint(center.getX(), center.getY());
Coordinate[] coordinates = new Coordinate[5];
for (int i = 0; i < 4; i++) {
geodeticCalculator.setDirection(-180 + i * 90 + 45, bufferRadiusMeters * Math.sqrt(2));
Point2D point2D = geodeticCalculator.getDestinationGeographicPoint();
coordinates[i] = new Coordinate(point2D.getX(), point2D.getY());
}
coordinates[4] = coordinates[0];
Polygon box = geometryFactory.createPolygon(coordinates);
Here is a simple solution that I used to generate bounding box coordinates that I use with GeoNames citieJSON API to get nearby big cities from a gps decimal coordinate.
This is a Java method from my GitHub repository: FusionTableModifyJava
I had a decimal GPS location and I needed to find the biggest city/state "near" that location. I needed a relatively accurate bounding box to pass to the citiesJSON GeoNames webservice to get back the biggest city in that bounding box. I pass the location and the "radius" I am interested in (in km) and it gives back the north, south, east, west decimal coordinates needed to pass to citiesJSON.
(I found these resources useful in doing my research:
Calculate distance, bearing and more between Latitude/Longitude points.
Longitude - Wikipedia)
It is not super accurate but accurate enough for what I was using it for:
// Compute bounding Box coordinates for use with Geonames API.
class BoundingBox
{
public double north, south, east, west;
public BoundingBox(String location, float km)
{
//System.out.println(location + " : "+ km);
String[] parts = location.replaceAll("\\s","").split(","); //remove spaces and split on ,
double lat = Double.parseDouble(parts[0]);
double lng = Double.parseDouble(parts[1]);
double adjust = .008983112; // 1km in degrees at equator.
//adjust = 0.008983152770714983; // 1km in degrees at equator.
//System.out.println("deg: "+(1.0/40075.017)*360.0);
north = lat + ( km * adjust);
south = lat - ( km * adjust);
double lngRatio = 1/Math.cos(Math.toRadians(lat)); //ratio for lng size
//System.out.println("lngRatio: "+lngRatio);
east = lng + (km * adjust) * lngRatio;
west = lng - (km * adjust) * lngRatio;
}
}
I'm new to GIS applications and I have a little problem. I'm trying to plot a polygon using geographic coordinates but I need to convert these coordinates to points before I can use them in plotting the polygon.
I don't know how to convert these coordinates to points to use for the polygon. I spent all my yesterday finding out how to do this but I really still don't get it.
I tried using the geography datatype in ms sql server 2008 but I couldn't find a java api in retrieving the polygon or the converted coordinates.
Please help me with a sample code on how to do this.
Thanks a lot people!!!
This is my code. 'Code'
double earth=6371;
double focal=500;
double lat= 47.653 ;
double lon = -122.358 ;
double latitude = lat*Math.PI/180;
double longitude = lon*Math.PI/180;
double x = earth * Math.sin(latitude)*Math.cos(longitude);
double y = earth * Math.sin(latitude)*Math.sin(longitude);
double z = earth * Math.cos(latitude);
double projectedX = x*focal /(focal+z);
double projectedY = y * focal / (focal+z);
int magx = (int) Math.round(projectedX * 5);
int magy = (int) Math.round(projectedY *5);
System.out.println ("MAG X : "+magx);
System.out.println ("MAG Y : "+magy);
I just plug in d mag x and y into my polygon but nothing comes up.
This is the syntax for creating and retrieving a geography Polygon in SQL Server from a set of n coordinates:
DECLARE #Polygon geography;
SET #Polygon = geography::STPolyFromText('POLYGON((Lon1 Lat1, Lon2 Lat2, ... Lonn Latn, Lon1 Lat1))', 4326);
SELECT #Polygon;
(This assumes you're using geographic coordinates relative to the WGS84 datum. If you don't know what that means, they probably are.)
I am trying to write a simple physics simulation where balls with varying radii and masses bounce around in a perfectly elastic and frictionless environment. I wrote my own code following this resource: http://www.vobarian.com/collisions/2dcollisions2.pdf and I also tested the code from here: Ball to Ball Collision - Detection and Handling
QUESTION EDITED
With the help of Rick Goldstein and Ralph, I have gotten my code to work (there was a typo..). Thanks so much for you help. However I am still confused as to why the other algorithm isn't working for me. The balls bounce off in the correct directions, but the total energy of the system is never conserved. The velocities get faster and faster until the balls just start blinking in static positions on the screen. I actually want to use this code in my program, because it is a lot more concise than the one I wrote.
Here is the functional algorithm that I wrote (although I did take the first bit from that other source). Its in a Bubble class:
public void resolveCollision(Bubble b)
{
// get the minimum translation distance
Vector2 delta = (position.subtract(b.position));
float d = delta.getMagnitude();
// minimum translation distance to push balls apart after intersecting
Vector2 mtd = delta.multiply(((getRadius() + b.getRadius())-d)/d);
// resolve intersection --
// inverse mass quantities
float im1 = 1 / getMass();
float im2 = 1 / b.getMass();
// push-pull them apart based off their mass
position = position.add(mtd.multiply(im1 / (im1 + im2)));
b.position = b.position.subtract(mtd.multiply(im2 / (im1 + im2)));
//get the unit normal and unit tanget vectors
Vector2 uN = b.position.subtract(this.position).normalize();
Vector2 uT = new Vector2(-uN.Y, uN.X);
//project ball 1 & 2 's velocities onto the collision axis
float v1n = uN.dot(this.velocity);
float v1t = uT.dot(this.velocity);
float v2n = uN.dot(b.velocity);
float v2t = uT.dot(b.velocity);
//calculate the post collision normal velocities (tangent velocities don't change)
float v1nPost = (v1n*(this.mass-b.mass) + 2*b.mass*v2n)/(this.mass+b.mass);
float v2nPost = (v2n*(b.mass-this.mass) + 2*this.mass*v1n)/(this.mass+b.mass);
//convert scalar velocities to vectors
Vector2 postV1N = uN.multiply(v1nPost);
Vector2 postV1T = uT.multiply(v1t);
Vector2 postV2N = uN.multiply(v2nPost);
Vector2 postV2T = uT.multiply(v2t);
//change the balls velocities
this.velocity = postV1N.add(postV1T);
b.velocity = postV2N.add(postV2T);
}
And here is the one that doesn't work
public void resolveCollision(Bubble b)
{
// get the minimum translation distance
Vector2 delta = (position.subtract(b.position));
float d = delta.getMagnitude();
// minimum translation distance to push balls apart after intersecting
Vector2 mtd = delta.multiply(((getRadius() + b.getRadius())-d)/d);
// resolve intersection --
// inverse mass quantities
float im1 = 1 / getMass();
float im2 = 1 / b.getMass();
// push-pull them apart based off their mass
position = position.add(mtd.multiply(im1 / (im1 + im2)));
b.position = b.position.subtract(mtd.multiply(im2 / (im1 + im2)));
// impact speed
Vector2 v = (this.velocity.subtract(b.velocity));
float vn = v.dot(mtd.normalize());
// sphere intersecting but moving away from each other already
if (vn > 0.0f) return;
// collision impulse (1f is the coefficient of restitution)
float i = (-(1.0f + 1f) * vn) / (im1 + im2);
Vector2 impulse = mtd.multiply(i);
// change in momentum
this.velocity = this.velocity.add(impulse.multiply(im1));
b.velocity = b.velocity.subtract(impulse.multiply(im2));
}
Let me know if you find anything. Thanks
Is there a typo in the line that sets v1nPost? Looks like the denominator should be this.mass + b.mass, not this.mass * b.mass.
Also, because you're computing a collision between this and b, are you checking to make sure you're not also doing the same collision between b and this, thus doubling the delta applied to each participating bubble in the collision?
I do a first guess: getMass() return an integer(or int) (and not a float or double)?
If this is true, than you problem is that 1 / getMass() will result in an integer value (and can be only 1 or most time 0)). To fix this replace 1 by 1.0 or 1.0f
Because the general rule is simple:
If you have a math operation (+,-,*,/) the resulting type will be integer if none of the both operants is a floating point data structure (double or float)
Anyway: there could be a second problem, may your calcualtion is not precise enougth. Then you should use double instead of float.
There is a part that looks strange:
The two calculations:
float v1nPost = (v1n*(this.mass-b.mass) + 2*b.mass*v2n)/(this.mass*b.mass);
float v2nPost = (v2n*(b.mass-this.mass) + 2*this.mass*v1n)/(this.mass+b.mass);
are symmetric, except the last operation, in the first it is * in the second it is +