Calculating distance in pixels between two locations - java

I'm trying to create a method which calculates the x and y in a grid and eventually the distance between that point and the middle. The problem is, I only know a few values. To explain the case a bit better an image:
(the values between '(..,..)' are lat/long combinations).
As you can see, I know the following values:
start of canvas: xy(0,0)
middle of canvas: xy(540,800) and lat/long(52.3702160, 4.8951680)
max dimension of canvas: x 1080, y 1600
point: xy(?,?) and lat/long(52.4167267, 4.8052174)
point: xy(?,?) and lat/long(52,2422306, 5.1129068)
First, I need to do something to calculate the missing x and y's from the points.
I already tried doing the following:
double mapWidth = screenWidth;
double mapHeight = screenHeight;
// get x value
x = (location.getLongitude()+180)*(mapWidth/360);
// convert from degrees to radians
double latRad = location.getLatitude()*Math.PI/180;
// get y value
double mercN = Math.log(Math.tan((Math.PI/4)+(latRad/2)));
y = (mapHeight/2)-(mapWidth*mercN/(2*Math.PI));
point = new PointF((float)x,(float)y);
This works but I'm getting the wrong x and y values.
For example if my points lat/long are further away the x and y's are getting bigger (more to the middle). But they need to be more at the side because the lat/long point is further away.
All lat/long points inside 2km diameter need to be in my grid, if the point is for example 0.9km away from the center it needs to be nearly at the side.
After that I need to calculate the distance between the two points. I already got that part using the following:
Math.sqrt((point.x - point2.x) * (point.x - point2.x) + (point.y - point2.y) * (point.y - point2.y));
My main problem is calculating the x and y from my lat/long points.
If anyone wants to help, thanks in advance!

I completely rethought my way of calculating the x and y.
I solved it by doing the following:
double distanceMeters = mCurrentLocation.distanceTo(location);
x = ((1000+distanceMeters)*mMiddleCoords.x)/1000; //1000 = radius.
y = ((1000+distanceMeters)*mMiddleCoords.y)/1000;

You can't directly use the distance formula from latitude and longitude. You'll have to take into account the curvature of the sphere to calculate the distance.
The minimum distance between two points on a sphere (and hence earth, simplifying it to a perfect sphere) is the length of the chord on what is called the Great Circle running through those points. A Great Circle is a circle with its center running through the center of the sphere).
From Wikipedia:
C = SQRT(X^2 + Y^2 + Z^2)
where:
X = cos(lat2) * cos(long2) - cos(lat1) * cos(long1)
Y = cos(lat2) * sin(long2) - cos(lat1) * sin(long1)
Z = sin(lat2) - sin(lat1)
And the distance is (2 * R * arcsin(C/2)) where R is the radius of the earth or 6371 km
The other alternative - if you know you will always have the Android libraries - is the Location.distanceTo() method.

Related

Convert longitude and latitude coordinates for world map image to cordinates (x , y) in pixel [duplicate]

I have a map of world.
I need to create a function that gets two double parameters (longitude and latitude) and that function should draw a small circle on that area in the map image.
I have the following info about the map:
The width of the map in pixels
The height of the map in pixels
** I get to pixel X, Y based on that image.
I tried longitude = -106.346771 and latitude = 56.130366;
mapWidth = 3840.0 and mapHeight = 2160.0 ;
double x = (longitude + 180) / 360 * mapWidth;
double y = (1 - Math.log(Math.tan(Math.toRadians(latitude)) + 1 /
Math.cos(Math.toRadians(latitude))) / Math.PI) / 2 * mapHeight;
result : [lon: -106.346771 lat: 56.130366]: X: 785.6344426666666 Y: 671.2084211650845
but not selected in right location.
enter image description here
Unfortunately, this problem is way harder than it seems.
That map is a Projection, so it is distorted from the original (roughly) spherical coordinate system your data is in.
(actually, your lat & long values may themselve be in one of several different projections, but that only really matters if you are doing very precise measurements.)
So your first order of business is to find out exactly what projection the map is using, then start looking for GIS libraries you can use in Java (I think there are several) to perform the translation.
Decide on a radius, r, for your globe model. Your map will be 2πr pixels wide.
Decide on a a latitude cutoff. You can't project a pole to a plane, and at extreme latitudes things get so distorted as to be unusable. 85 degrees is a common choice.
Express your latitude in radians: lat_r
You X coordinate is r * (lat_r+ π). So at 180° W your X coordinate is r * (-π + π) = 0, and at 180° E your X coordinate is r * (π + π) = 2πr
Express your longitude in radians: lon_r
Your Y coordinate is r * tan(lon_r) * (1 - cos(lon_r)). So at 85° N your Y coordinate is r * tan(1.4835) * (1 - cos(1.4835)) = 10.4r

Simple way to resolve 2D elastic collision between circles

I need the simplest solution for resolving 2D elastic collision between circles, each circle has equal mass with the others.
The environment is Android canvas in which the Y axis is growing towards down. Logic representation of the circle is class PlayerBall which has successful collision detection. PlayerBall has fields:
x and y position of center of the circle
velX and velY velocity vector of the circle movement represented as two scalar values which can be positive or negative.
diameter - diameter of the circle
public static void resolveCollision(PlayerBall ballOne, PlayerBall ballTwo)
{
double collisionAngle = Math.atan2(ballTwo.y - ballOne.y, ballTwo.x - ballOne.x); // angle for ball one
// calculating new velocities between ballOne and ballTwo
...
// setting the new velocities for both balls
ballOne.setVelocity((float)ballOneVelX, (float)ballOneVelY);
ballTwo.setVelocity((float)ballTwoVelX, (float)ballwTwoVelY);
}
I am expecting that velocities of the balls change according to formula defined in this article https://en.wikipedia.org/wiki/Elastic_collision#Two-dimensional_collision_with_two_moving_objects
If you know the x and y velocity of both masses then you don't actually need the angle of collision. The resultant x and y forces on the balls can be calculated as a product of their respective masses, and velocities.
You can define this relationship by the formula:
Where V_x1 represents the velocity purely in the x plane, m1 and m2 are the masses of the balls. This will give you the resultant x velocity. You can apply the same logic to calculate the resultant forces in the y direction.
let newVelX1 = (vel1.vX * (m1 - m2) + (2 * m2 * vel2.vX)) / (m1 + m2);
let newVelY1 = (vel1.vY * (m1 - m2) + (2 * m2 * vel2.vY)) / (m1 + m2);

Converting longitude and latitude coordinates to map pixels (X and Y) the right way

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.

Why isn't this code allowing me to connect the vertices of the drawing?

I'm meant to draw a pentagon with lines going from the vertices to the centre. These 'arms' are being drawn correctly but when I try to connect the vertices it is being drawn incorrectly. To connect the lines I placed another draw function in the loop as below, which should take the end point coordinates of the first line drawn as the starting point, and the end point coordinates of the next 'arm' that is drawn in the iteration, as its end point. Am I missing something here? Am I wrong the use 'i+angle' in the second draw?
for (int i = 0; i < arms; i += angle) {
double endPointX = armLength * Math.cos(i*angle-Math.PI/2);
double endPointY = armLength * Math.sin(i*angle-Math.PI/2);
double endPointX2 = armLength * Math.cos((i+angle)*angle-Math.PI/2);
double endPointY2 = armLength * Math.sin((i+angle)*angle-Math.PI/2);
g2d.drawLine(centreX, centreY,centreX+ (int) endPointX,centreY+ (int) endPointY);
g2d.drawLine(centreX+ (int) endPointX,centreY+ (int) endPointY, (int) endPointX2,(int) endPointY2);
}
I have a solution for this here in PolygonFactory
Abstractly, the way to generate a regular polygon with n points is to put these points on the unit circle. So:
Calculate your angle step, which is 2 * pi / #vertices
Calculate your radius
Starting at angle 0 (or an offset if you want) use Math.sin(angle) and Math.cos(angle) to calculate the x and y coordinates of your vertices
Store the vertex points somewhere / somehow. If you look at the Polygon class or the class I wrote, you can get some ideas on how to do this in a way that is friendly to converting to a java.awt.Polygon.

JAVA elastic collision of moving and non moving circles

I'm trying to write a java mobile application (J2ME) and I got stuck with a problem: in my project there are moving circles called shots, and non moving circles called orbs. When a shot hits an orb, it should bounce off by classical physical laws. However I couldn't find any algorithm of this sort.
The movement of a shot is described by velocity on axis x and y (pixels/update). all the information about the circles is known: their location, radius and the speed (on axis x and y) of the shot.
Note: the orb does not start moving after the collision, it stays at its place. The collision is an elastic collision between the two while the orb remains static
here is the collision solution method in class Shot:
public void collision(Orb o)
{
//the orb's center point
Point oc=new Point(o.getTopLeft().x+o.getWidth()/2,o.getTopLeft().y+o.getWidth()/2);
//the shot's center point
Point sc=new Point(topLeft.x+width/2,topLeft.y+width/2);
//variables vx and vy are the shot's velocity on axis x and y
if(oc.x==sc.x)
{
vy=-vy;
return ;
}
if(oc.y==sc.y)
{
vx=-vx;
return ;
}
// o.getWidth() returns the orb's width, width is the shot's width
double angle=0; //here should be some sort of calculation of the shot's angle
setAngle(angle);
}
public void setAngle(double angle)
{
double v=Math.sqrt(vx*vx+vy*vy);
vx=Math.cos(Math.toRadians(angle))*v;
vy=-Math.sin(Math.toRadians(angle))*v;
}
thanks in advance for all helpers
At the point of collision, momentum, angular momentum and energy are preserved. Set m1, m2 the masses of the disks, p1=(p1x,p1y), p2=(p2x,p2y) the positions of the centers of the disks at collition time, u1, u2 the velocities before and v1,v2 the velocities after collision. Then the conservation laws demand that
0 = m1*(u1-v1)+m2*(u2-v2)
0 = m1*cross(p1,u1-v1)+m2*cross(p2,u2-v2)
0 = m1*dot(u1-v1,u1+v1)+m2*dot(u2-v2,u2+v2)
Eliminate u2-v2 using the first equation
0 = m1*cross(p1-p2,u1-v1)
0 = m1*dot(u1-v1,u1+v1-u2-v2)
The first tells us that (u1-v1) and thus (u2-v2) is a multiple of (p1-p2), the impulse exchange is in the normal or radial direction, no tangential interaction. Conservation of impulse and energy now leads to a interaction constant a so that
u1-v1 = m2*a*(p1-p2)
u2-v2 = m1*a*(p2-p1)
0 = dot(m2*a*(p1-p2), 2*u1-m2*a*(p1-p2)-2*u2+m1*a*(p2-p1))
resulting in a condition for the non-zero interaction term a
2 * dot(p1-p2, u1-u2) = (m1+m2) * dot(p1-p2,p1-p2) * a
which can now be solved using the fraction
b = dot(p1-p2, u1-u2) / dot(p1-p2, p1-p2)
as
a = 2/(m1+m2) * b
v1 = u1 - 2 * m2/(m1+m2) * b * (p1-p2)
v2 = u2 - 2 * m1/(m1+m2) * b * (p2-p1)
To get the second disk stationary, set u2=0 and its mass m2 to be very large or infinite, then the second formula says v2=u2=0 and the first
v1 = u1 - 2 * dot(p1-p2, u1) / dot(p1-p2, p1-p2) * (p1-p2)
that is, v1 is the reflection of u1 on the plane that has (p1-p2) as its normal. Note that the point of collision is characterized by norm(p1-p2)=r1+r2 or
dot(p1-p2, p1-p2) = (r1+r2)^2
so that the denominator is already known from collision detection.
Per your code, oc{x,y} contains the center of the fixed disk or orb, sc{x,y} the center and {vx,vy} the velocity of the moving disk.
Compute dc={sc.x-oc.x, sc.y-oc.y} and dist2=dc.x*dc.x+dc.y*dc.y
1.a Check that sqrt(dist2) is sufficiently close to sc.radius+oc.radius. Common lore says that comparing the squares is more efficient. Fine-tune the location of the intersection point if dist2 is too small.
Compute dot = dc.x*vx+dcy*vy and dot = dot/dist2
Update vx = vx - 2*dot*dc.x, vy = vy - 2*dot*dc.y
The special cases are contained inside these formulas, e.g., for dc.y==0, that is, oc.y==sc.y one gets dot=vx/dc.x, so that vx=-vx, vy=vy results.
Considering that one circle is static I would say that including energy and momentum is redundant. The system's momentum will be preserved as long as the moving ball contains the same speed before and after the collision. Thus the only thing you need to change is the angle at which the ball is moving.
I know there's a lot of opinions against using trigonometric functions if you can solve the issue using vector math. However, once you know the contact point between the two circles, the trigonometric way of dealing with the issue is this simple:
dx = -dx; //Reverse direction
dy = -dy;
double speed = Math.sqrt(dx*dx + dy*dy);
double currentAngle = Math.atan2(dy, dx);
//The angle between the ball's center and the orbs center
double reflectionAngle = Math.atan2(oc.y - sc.y, oc.x - sc.x);
//The outcome of this "static" collision is just a angular reflection with preserved speed
double newAngle = 2*reflectionAngle - currentAngle;
dx = speed * Math.cos(newAngle); //Setting new velocity
dy = speed * Math.sin(newAngle);
Using the orb's coordinates in the calculation is an approximation that gains accuracy the closer your shot is to the actual impact point in time when this method is executed. Thus you might want to do one of the following:
Replace the orb's coordinates by the actual point of impact (a tad more accurate)
Replace the shot's coordinates by the position it has exactly when the impact will/did occur. This is the best scenario in respect to the outcome angle, however may lead to slight positional displacements compared to a fully realistic scenario.

Categories