题
我有产生谷歌地图一些C#代码。这个代码看着我需要在地图上绘制的所有点,然后工作了矩形的界限,包括那些点。然后将其传递此范围的谷歌地图API以适当地设置缩放级别来显示所有的点在地图上。
此代码工作正常,但是我有一个新的要求。
其中一点可以具有与其相关联的精度。如果是这样的话,那么我周围画点的圆与设置精度值半径。同样,这工作正常但是我的边界检查现在没有做什么,我想要它做的。我想有边框包括完整的圆。
此需要一种算法来采取一个点x和计算点y,将通过z米北的x和也ž米路南x的。
没有人有该算法中,优选在C#。我没有找到一个通用的算法这里,但我似乎已经无法正常实现这个作为我的答案正在逐渐公里漂泊的是1000。
这是通用示例
Lat/lon given radial and distance
A point {lat,lon} is a distance d out on the tc radial from point 1 if:
lat=asin(sin(lat1)*cos(d)+cos(lat1)*sin(d)*cos(tc))
IF (cos(lat)=0)
lon=lon1 // endpoint a pole
ELSE
lon=mod(lon1-asin(sin(tc)*sin(d)/cos(lat))+pi,2*pi)-pi
ENDIF
这是我的C#转换。
// Extend a Point North/South by the specified distance
public static Point ExtendPoint(Point _pt, int _distance, int _bearing )
{
Decimal lat = 0.0;
Decimal lng = 0.0;
lat = Math.Asin(Math.Sin(_pt.Lat) * Math.Cos(_distance) + Math.Cos(_pt.Lat) *
Math.Sin(_distance) * Math.Cos(_bearing));
if (Math.Cos(lat) == 0)
{
lng = _pt.Lng; // endpoint a pole
}
else
{
lng = (
(_pt.Lng - Math.Asin(Math.Sin(_bearing) * Math.Sin(_distance) / Math.Cos(lat))
+ Math.PI) % (2 * Math.PI)) - Math.PI;
}
ret = new Point(lat,lng);
return ret;
}
我打电话为0的轴承此函数来计算新的偏北位置和180°的值来计算新的南纬。
无论是任何人都可以看到我做错了或者是提供一个可正常工作的算法?
解决方案
如果你有一个给定的经度和纬度可以计算出的x公里变化的正确的纬度和经度在像这样纬度:
new-lat = ((old-km-north + x-km-change)/40,075) * 360)
^ is the ratio of the ^ times the ratio of the circle
of the earth the change by 360 to get the total ratio
covers. covered in degrees.
同样可以适用于经度。如果你有总距离加的变化,你可以用类似的方式计算总度。
new-long = ((old-km-east + x-km-change)/40,075) * 360)
^ is the ratio of the ^ times the ratio of the circle
of the earth the change by 360 to get the total ratio
covers. covered in degrees.
此外,这些计算应该工作,但是我在这里流失纯粹的直觉,但逻辑似乎是成立的。
编辑:作为使用2.pi.r.cos(LAT)或40074.cos通过Skizz指出40075只需要被调整到地球的周长在任何给定纬度(LAT)
其他提示
我具有非常相似的一段代码。相比于另一种实现方式时,这让我非常接近的结果。
我认为与你的问题是,使用的是“距离”,作为以弧度以米为单位直线距离,而不是角距离。
/// <summary>
/// Calculates the end-point from a given source at a given range (meters) and bearing (degrees).
/// This methods uses simple geometry equations to calculate the end-point.
/// </summary>
/// <param name="source">Point of origin</param>
/// <param name="range">Range in meters</param>
/// <param name="bearing">Bearing in degrees</param>
/// <returns>End-point from the source given the desired range and bearing.</returns>
public static LatLonAlt CalculateDerivedPosition(LatLonAlt source, double range, double bearing)
{
double latA = source.Latitude * UnitConstants.DegreesToRadians;
double lonA = source.Longitude * UnitConstants.DegreesToRadians;
double angularDistance = range / GeospatialConstants.EarthRadius;
double trueCourse = bearing * UnitConstants.DegreesToRadians;
double lat = Math.Asin(
Math.Sin(latA) * Math.Cos(angularDistance) +
Math.Cos(latA) * Math.Sin(angularDistance) * Math.Cos(trueCourse));
double dlon = Math.Atan2(
Math.Sin(trueCourse) * Math.Sin(angularDistance) * Math.Cos(latA),
Math.Cos(angularDistance) - Math.Sin(latA) * Math.Sin(lat));
double lon = ((lonA + dlon + Math.PI) % UnitConstants.TwoPi) - Math.PI;
return new LatLonAlt(
lat * UnitConstants.RadiansToDegrees,
lon * UnitConstants.RadiansToDegrees,
source.Altitude);
}
其中
public const double EarthRadius = 6378137.0; // WGS-84 ellipsoid parameters
和LatLonAlt是以度/米(转换发生在内部)。 根据需要进行调整。
我想你能想出什么UnitConstants.DegreesToRadians
值:)
有关懒惰的人,(像我))一个复制粘贴的解决方案,埃里希·米拉瓦尔的版本具有非常小的变化:
using System.Device.Location; // add reference to System.Device.dll
public static class GeoUtils
{
/// <summary>
/// Calculates the end-point from a given source at a given range (meters) and bearing (degrees).
/// This methods uses simple geometry equations to calculate the end-point.
/// </summary>
/// <param name="source">Point of origin</param>
/// <param name="range">Range in meters</param>
/// <param name="bearing">Bearing in degrees</param>
/// <returns>End-point from the source given the desired range and bearing.</returns>
public static GeoCoordinate CalculateDerivedPosition(this GeoCoordinate source, double range, double bearing)
{
var latA = source.Latitude * DegreesToRadians;
var lonA = source.Longitude * DegreesToRadians;
var angularDistance = range / EarthRadius;
var trueCourse = bearing * DegreesToRadians;
var lat = Math.Asin(
Math.Sin(latA) * Math.Cos(angularDistance) +
Math.Cos(latA) * Math.Sin(angularDistance) * Math.Cos(trueCourse));
var dlon = Math.Atan2(
Math.Sin(trueCourse) * Math.Sin(angularDistance) * Math.Cos(latA),
Math.Cos(angularDistance) - Math.Sin(latA) * Math.Sin(lat));
var lon = ((lonA + dlon + Math.PI) % (Math.PI*2)) - Math.PI;
return new GeoCoordinate(
lat * RadiansToDegrees,
lon * RadiansToDegrees,
source.Altitude);
}
private const double DegreesToRadians = Math.PI/180.0;
private const double RadiansToDegrees = 180.0/ Math.PI;
private const double EarthRadius = 6378137.0;
}
用法:
[TestClass]
public class CalculateDerivedPositionUnitTest
{
[TestMethod]
public void OneDegreeSquareAtEquator()
{
var center = new GeoCoordinate(0, 0);
var radius = 111320;
var southBound = center.CalculateDerivedPosition(radius, -180);
var westBound = center.CalculateDerivedPosition(radius, -90);
var eastBound = center.CalculateDerivedPosition(radius, 90);
var northBound = center.CalculateDerivedPosition(radius, 0);
Console.Write($"leftBottom: {southBound.Latitude} , {westBound.Longitude} rightTop: {northBound.Latitude} , {eastBound.Longitude}");
}
}
我不知道如果我失去了一些东西,但我想作为,“我有一个经/纬度点问题可以改写的,我想北找到点x米,X米路南的该点“。
如果是这样的问题,那么你并不需要找到一个新的经度(这让事情变得更简单),你只需要一个新的纬度。纬度的程度大致是60海里长地球上的任何地方,并且海里是1852米。因此,对于新的纬度X米,南北:
north_lat = lat + x / (1852 * 60)
north_lat = min(north_lat, 90)
south_lat = lat - x / (1852 * 60)
south_lat = max(south_lat, -90)
这是不完全精确,因为地球不与恰好60海里纬度的每度之间的理想球体。然而,其他的答案假设纬线是等距的,所以我假设你不关心这个。如果你有兴趣有多大错误可能会引入,对维基百科的一个很好的表,其中显示在此链接“在纬度每1°的变化距离”的不同纬度:
有与埃德威廉相当真棒网站两个方程问题...但我没有对它们进行分析,看看为什么。
第三方程我发现这里似乎给正确的结果
下面是测试用例在PHP ...第三方程是正确的,前两个似地给予不正确的值对于经度。
<?php
$lon1 = -108.553412; $lat1 = 35.467155; $linDistance = .5; $bearing = 170;
$lon1 = deg2rad($lon1); $lat1 = deg2rad($lat1);
$distance = $linDistance/6371; // convert dist to angular distance in radians
$bearing = deg2rad($bearing);
echo "lon1: " . rad2deg($lon1) . " lat1: " . rad2deg($lat1) . "<br>\n";
// doesn't work
$lat2 = asin(sin($lat1) * cos($distance) + cos($lat1) * sin($distance) * cos($bearing) );
$dlon = atan2(sin($bearing) * sin($distance) * cos($lat1), cos($distance) - sin($lat1) * sin($lat2));
$lon2 = (($lon1 - $dlon + M_PI) % (2 * M_PI)) - M_PI; // normalise to -180...+180
echo "lon2: " . rad2deg($lon2) . " lat2: " . rad2deg($lat2) . "<br>\n";
// same results as above
$lat3 = asin( (sin($lat1) * cos($distance)) + (cos($lat1) * sin($distance) * cos($bearing)));
$lon3 = (($lon1 - (asin(sin($bearing) * sin($distance) / cos($lat3))) + M_PI) % (2 * M_PI)) - M_PI;
echo "lon3: " . rad2deg($lon3) . " lat3: " . rad2deg($lat3) . "<br>\n";
// gives correct answer... go figure
$lat4 = asin(sin($lat1) * cos($linDistance/6371) + cos($lat1) * sin($linDistance/6371) * cos($bearing) );
$lon4 = $lon1 + atan2( (sin($bearing) * sin($linDistance/6371) * cos($lat1) ), (cos($linDistance/6371) - sin($lat1) * sin($lat2)));
echo "lon4: " . rad2deg($lon4) . " lat4: " . rad2deg($lat4) . "<br>\n";
?>
注意我收到通过电子邮件从作者(爱德华·威廉姆斯)的前两个方程:强>
这是我的 “实施注意事项”:
注意在MOD函数。这似乎是在不同的实现方式 不同的语言,具有不同的约定上的是否符号 结果如下除数或被除数的符号。 (我们想要的标志 跟随除数或者是欧氏。 C'S FMOD和Java的%不工作。) 在本文档中,MOD(Y,X)是由x和总是分割ÿ剩余 位于范围0 <= MOD
如果你有一个地板函数(在Excel INT),它返回地板(X)= “最大整数小于或等于x”例如地板(-2.3)= - 3和 地板(2.3)= 2
mod(y,x) = y - x*floor(y/x)
下面的应在没有地板的工作函数 - 不管 是否 “INT” 截短物或轮向下:
mod=y - x * int(y/x)
if ( mod < 0) mod = mod + x
PHP是类似于C FMOD并执行它的 “错误” 我的目的。
有更准确如果首先重新投影它 UTM 并然后检查距离。
希望这有助于