I'm trying to draw a square around a given point on the earth's surface.
I'm using information I retrieved from here and here and ultimately came up with this:-
// Converting degrees to radians
double latInDecimals = (Math.PI / 180) * latitude;
double longInDecimals = (Math.PI / 180) * longitude;
List<string> lstStrCoords = new List<string>();
double changeInLat;
double changeInLong;
double lineOfLat;
// Calculating change in latitude for square of side
changeInLong = (side / 1000) * (360.0 / 40075);
// Calculating length of longitude at that point of latitude
lineOfLat = Math.Cos(longitude) * 40075;
// Calculating change in longitude for square of side 'side'
changeInLat = (side / 1000) * (360.0 / lineOfLat);
// Converting changes into radians
changeInLat = changeInLat * (Math.PI / 180);
changeInLong = changeInLong * (Math.PI / 180);
double nLat = changeInLat * (Math.Sqrt(2) / 2);
double nLong = changeInLong * (Math.Sqrt(2) / 2);
double coordLat1 = latInDecimals + nLat;
double coordLong1 = longInDecimals + nLong;
double coordLat2 = latInDecimals + nLat;
double coordLong2 = longInDecimals - nLong;
double coordLat3 = latInDecimals - nLat;
double coordLong3 = longInDecimals - nLong;
double coordLat4 = latInDecimals - nLat;
double coordLong4 = longInDecimals + nLong;
// Converting coords back to degrees
coordLat1 = coordLat1 * (180 / Math.PI);
coordLat2 = coordLat2 * (180 / Math.PI);
coordLat3 = coordLat3 * (180 / Math.PI);
coordLat4 = coordLat4 * (180 / Math.PI);
coordLong1 = coordLong1 * (180 / Math.PI);
coordLong2 = coordLong2 * (180 / Math.PI);
coordLong3 = coordLong3 * (180 / Math.PI);
coordLong4 = coordLong4 * (180 / Math.PI);
Now even though this works, the polygon that I get from joining these is a rectangle.
I'm confused as to what's wrong with my code.
A rectangle of one degree of latitude and longitude on the sphere has not the same length in km unless it is situated on the equator. It gets narrower towards the poles. If you want to make both sides the same size you have to make a correction
longitudinal_length = latitudinal_length / cos(latitude)
So you will need to divide your longitudinal length of your square by cos(latitude).
Now, your square might still be crooked, but this depends on how the map is projected and this is a completely different story. You would need to know the projection formulas used by Google to make a correction.
You may find more complicated formulas that take account of the fact that the earth is not a perfect sphere, but I think that this should be sufficient for your position marker. Note also that you will get a division by zero at +/-90 degree. So placing a rectangle on a pole requires another approach.
From: IBM Knowledge Center / Geographic coordinate system / Figure 4. Different dimensions between locations on the graticule
Related
I'm trying to place some icons equally on the upper half of a circle.
I managed to place them around a whole circle with the following formula/code
for(int i=0;i<numberOfItems;i++)
{
float x = (float)(center.X + radius * Math.Cos(2 * Math.PI * i / numberOfItems))-iconBmp.Width/2;
float y = (float)(center.Y + radius * Math.Sin(2 * Math.PI * i/ numberOfItems))-iconBmp.Height/2;
canvas.DrawBitmap(iconBmp, new SKPoint(x, y));
}
But I can't figure how to do it for just the upper half of the circle?
Is there a formula for that as well?
I have the feeling that the one I have for the whole circle just needs some adjustment to achieve that...but can't figure what.
Thank you already!
This is more a math question than a programming question.
2pi radians = 360 degrees
So if you want all of the items shown, but the shape to be a half circle, then use:
Math.PI * i / numberOfItems instead of 2 * Math.PI * i / numberOfItems
Also because screen coordinates start in the top-left corner. That will make it the bottom half of the circle with the first item on the right. If you want the top half of the circle with the first item on the left, then just add pi:
Math.PI + (Math.PI * i / numberOfItems)
Whole code:
for(int i=0;i<numberOfItems;i++)
{
float x = (float)(center.X + radius * Math.Cos(Math.PI + (Math.PI * i / numberOfItems)))-iconBmp.Width/2;
float y = (float)(center.Y + radius * Math.Sin(Math.PI + (Math.PI * i / numberOfItems)))-iconBmp.Height/2;
canvas.DrawBitmap(iconBmp, new SKPoint(x, y));
}
Let's say I have 2 coordinates that are ~222.33 meters away from each other :
A: 49.25818, -123.20626
B: 49.25813, -123.2032
Those 2 points makes a segment.
How can I calculate the coordinate of point Z that is X meters away from either A or B but towards the other point?
I already know the distance between my 2 points using System.Device.Location library.
GeoCoordinate A = new GeoCoordinate(49.25818, -123.20626);
GeoCoordinate B = new GeoCoordinate(49.25813, -123.2032);
var distanceInMeters = A.GetDistanceTo(B);
// distanceInMeters = 222.33039783713738
I'm looking for something like this:
GeoCoordinate GetPointTowards(GeoCoordinate fromPoint, GeoCoordinate towardPoint, double distanceInMeter) {
[???]
}
I think I may need the bearing or something to be able to get the new point location.
Most examples I've found are for iOS, Android or GMaps with specific libraries..
Here's an outline of how I would do it. With this approach, there is no need to explicitly deal with the difference in units between coordinates and distances because taking the ratio of target to total distance eliminates the unit.
totalDistance = distance in meters between point A and point B.
targetDistance = distance in meters to travel from point A to point B
ratio = targetDistance / totalDistance
diffX = B.X - A.X
diffY = B.Y - A.Y
targetX = A.X + (ratio * diffX)
targetY = A.Y + (ratio * diffY)
But this wouldn't handle the edge cases like being at 179 degrees longitude and adding 3 degrees which would put you at -178 longitude.
This is my code converted to C# from http://www.movable-type.co.uk/scripts/latlong.html. The fraction is from 0 to 1 and is the fraction along the distance from the first point to the second point the output position will be. You could always modify it to take a straight distance value.
public static (double Lat, double Lon) IntermediatePoint((double Lat, double Lon) StartPoint, (double Lat, double Lon) EndPoint, double fraction)
{
if (fraction < 0 || fraction > 1)
throw new ArgumentOutOfRangeException();
double angDist = Distance(StartPoint, EndPoint) / radius;
double lat1 = StartPoint.Lat * (Math.PI / 180);
double lon1 = StartPoint.Lon * (Math.PI / 180);
double lat2 = EndPoint.Lat * (Math.PI / 180);
double lon2 = EndPoint.Lon * (Math.PI / 180);
double a = Math.Sin((1 - fraction) * angDist) / Math.Sin(angDist);
double b = Math.Sin(fraction * angDist) / Math.Sin(angDist);
double x = a * Math.Cos(lat1) * Math.Cos(lon1) + b * Math.Cos(lat2) * Math.Cos(lon2);
double y = a * Math.Cos(lat1) * Math.Sin(lon1) + b * Math.Cos(lat2) * Math.Sin(lon2);
double z = a * Math.Sin(lat1) + b * Math.Sin(lat2);
double lat3 = Math.Atan2(z, Math.Sqrt(Math.Pow(x, 2) + Math.Pow(y, 2)));
double lon3 = Math.Atan2(y, x);
return (lat3 * (180 / Math.PI), lon3 * (180 / Math.PI));
}
public static double Distance((double Lat, double Lon) point1, (double Lat, double Lon) point2)
{
double φ1 = point1.Lat * (Math.PI / 180.0);
double φ2 = point2.Lat * (Math.PI / 180.0);
double Δφ = (point2.Lat - point1.Lat) * (Math.PI / 180.0);
double Δλ = (point2.Lon - point1.Lon) * (Math.PI / 180.0);
double a = Math.Sin(Δφ / 2) * Math.Sin(Δφ / 2) + Math.Cos(φ1) * Math.Cos(φ2) * Math.Sin(Δλ / 2) * Math.Sin(Δλ / 2);
double c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
return radius * c;
}
radius is a constant representing the Earth's radius in meters.
I wrote this extension method for an IPoint.
public static IPoint Offset(this IPoint point, double angle, double distanceInMeters)
{
var radians = Math.PI * angle / 180;
var distanceX = distanceInMeters * Math.Cos(radians);
var distanceY = distanceInMeters * Math.Sin(radians);
var earthRadius = 6371000;
var y = point.Y + ((distanceY / earthRadius) * 180 / Math.PI);
var x = point.X + ((distanceX / (earthRadius * Math.Cos(y * 180 / Math.PI))) * 180 / Math.PI);
return new Point(x, y);
}
It works fine when I am putting in an angle of 0, 90, 180 and 270, then it return a coordinate at the given distance away from the starting point. But when I am starting to go in an angle that do not point exactly North, East etc. Iam getting wrong distances.
Where do I go wrong ?
Alternative is there some libraries to use?
Try this formula. As I consider you should transfer latitude and longitude to radians and then back to degrees.
public static Point Offset(this Point point, double angle, double distanceInMeters)
{
double rad = Math.PI * angle / 180;
double xRad = Math.PI * point.X / 180; // convert to radians
double yRad = Math.PI * point.Y / 180;
double R = 6378100; //Radius of the Earth in meters
double x = Math.Asin(Math.Sin(xRad) * Math.Cos(distanceInMeters/ R)
+ Math.Cos(xRad) * Math.Sin(distanceInMeters/ R) * Math.Cos(rad));
double y = yRad + Math.Atan2(Math.Sin(rad) * Math.Sin(distanceInMeters/ R) * Math.Cos(xRad), Math.Cos(distanceInMeters/ R) - Math.Sin(xRad) * Math.Sin(x));
x = x * 180 / Math.PI; // convert back to degrees
y = y * 180 / Math.PI;
return new Point(x, y);
}
Im using Microsoft visual studio 2010, with the refernce dynamic data display.
I would like to draw a circle on a map, i have 2 points, one of them is the center of the circle and the other is the point on the circle, the distance between them is the radius of the circle.
the result should look like this :
http://sizmedia.com/my.php?i=mjmynzim2nhy.png
my result when I draw a circle with one point and const distance is like this (distance = radius = 15):
http://sizmedia.com/my.php?i=hm2zuv5yyenj.png
***** I don't care if the circle will look like my result(the ellipse)
because as I understood the earth is circle and its type of reasonable. ****
but when I draw circle with distance between 2 point (distance = 3400 +) I can't see the circle that I draw.
I would love to get some help, there is my code to find distance between 2 points.
// Calculating the distance between the two points
double dLat = (ps.X - centerPoint.X) / 180 * Math.PI;
double dLong = (
double.Parse(this.plotter.Viewport.Transform.DataTransform.ViewportToData(ps).Y.ToString()) -
double.Parse(this.plotter.Viewport.Transform.DataTransform.ViewportToData(centerPoint).Y.ToString())) / 180 * Math.PI;
double a = Math.Sin(dLat / 2) * Math.Sin(dLat / 2)
+ Math.Cos(ps.X / 180 * Math.PI) * Math.Cos(pointLine1.X / 180 * Math.PI)
* Math.Sin(dLong / 2) * Math.Sin(dLong / 2);
double c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
//Calculate radius of earth
double radiusE = 6378135; // Equatorial radius, in metres
double radiusP = 6356750; // Polar Radius
//Numerator part of function
double nr = Math.Pow(radiusE * radiusP * Math.Cos(ps.X / 180 * Math.PI), 2);
//Denominator part of the function
double dr = Math.Pow(radiusE * Math.Cos(ps.X / 180 * Math.PI), 2)
+ Math.Pow(radiusP * Math.Sin(ps.X / 180 * Math.PI), 2);
double radius = Math.Sqrt(nr / dr);
//Calculate distance in meters.
distance = (radius * c); // resualt in meters
distance /= 1000; // resualt in KM
And there is my code to add the circle :
while (a < 360) // Doing one round around the point (The angels)
{
// Get the X position of the pointClicked
cx = (double)prePs.X;
// Get the Y position of the pointClicked
cy = double.Parse(this.plotter.Viewport.Transform.DataTransform.ViewportToData(prePs).Y.ToString());
// Get the new X position of the pointClicked by the angel with math calculation
xEndP = (float)(distance * Math.Cos(a * Math.PI / 180F)) + cx;
// Get the new Y position of the pointClicked by the angel with math calculation
yEndP = (float)(distance * Math.Sin(a * Math.PI / 180F)) + cy;
// Creating the new point
globalPoint = new DraggablePoint(new Point(xEndP, yEndP));
globalPoint.Position = new Point(xEndP, yEndP);
globalPoint.Visibility = Visibility.Visible;
// Increas the angel
a++;
//Creat new point on the circle with new angel
xEndPNext = (float)(distance * Math.Cos(a * Math.PI / 180F)) + cx;
yEndPNext = (float)(distance * Math.Sin(a * Math.PI / 180F)) + cy;
// Creat line between the two new points that we creat now
segmentHelper = new Segment(new Point(xEndP, yEndP), new Point(xEndPNext, yEndPNext));
// Brush between the points by line
SolidColorBrush mySolidColorBrush = new SolidColorBrush();
mySolidColorBrush.Color = Color.FromArgb(255, 47, 79, 49);
segmentHelper.Stroke = mySolidColorBrush;
// Add the line to the chartplotter
plotter.Children.Add(segmentHelper);
// Add the angel
a++;
}
My algorithm is take one point, and the next point and to draw line between them ( when the points are visiblty false) and then i get a nice circle.
Thank you very much :)
Currently i am converting a Desktop application to Windows 8 application. To get a angle between 2 points in desktop application they use Vector.AngleBetween(vector1, vector2). Using "Point" i got the vector values in WinRT. Like this,
var vectorX = point1.X - point2.X;
var vectorY = point1.Y - point2.Y;
Point vector = new Point(vectorX , vectorY);
But i don't find any way to get a angle between 2 points in WinRT. I got this function from online,
public double GetAngleOfLineBetweenTwoPoints(Point p1, Point p2)
{
var xDiff = p2.X - p1.X;
var yDiff = p2.Y - p1.Y;
return Math.Atan2(yDiff , xDiff) * (180 / Math.PI);
}
but it wont give the exact result like "Vector.AngleBetween". Is there any better way available to get a result like "Vector.AngleBetween" in WinRT...?
I don't think your math is right. You can calculate angle between vectors using dot product and arcus cosinus, pseudo-code below:
double vectorALength = sqrt(vectorA.x * vectorA.x + vectorA.y * vectorA.y);
double vectorBLength = sqrt(vectorB.x * vectorB.x + vectorB.y * vectorB.y);
double dotProduct = vectorA.x * vectorB.x + vectorA.y + vectorB.y
double cosAngle = dotProduct / (vectorALength * vectorBLength);
double angle = Math.Acos(cosAngle) * (180 / Math.PI);
If I'm correct this should give you roughly right answer. Details and better explenations can be found on internet, e.g. Dot product