using System;
using ESRI.ArcGIS.Client.Geometry; namespace GISProject.Extensions
{
/// <summary>
/// Extension methods for geodesic calculations.
/// </summary>
public static class Geodesic
{
private const double EarthRadius = 6378.137; //kilometers. Change to miles to return all values in miles instead /// <summary>
/// Gets the distance between two points in Kilometers.
/// </summary>
/// <param name="start">The start point.</param>
/// <param name="end">The end point.</param>
/// <returns></returns>
public static double GetSphericalDistance(this MapPoint start, MapPoint end)
{
double lon1 = start.X / 180 * Math.PI;
double lon2 = end.X / 180 * Math.PI;
double lat1 = start.Y / 180 * Math.PI;
double lat2 = end.Y / 180 * Math.PI;
return 2 * Math.Asin(Math.Sqrt(Math.Pow((Math.Sin((lat1 - lat2) / 2)), 2) +
Math.Cos(lat1) * Math.Cos(lat2) * Math.Pow(Math.Sin((lon1 - lon2) / 2), 2))) * EarthRadius;
}
/// <summary>
/// Returns a polygon with a constant distance from the center point measured on the sphere.
/// </summary>
/// <param name="center">The center.</param>
/// <param name="distKM">Radius in kilometers.</param>
/// <returns></returns>
public static Polygon GetRadiusAsPolygon(this MapPoint center, double distKM)
{
Polyline line = GetRadius(center, distKM);
Polygon poly = new Polygon(); if (line.Paths.Count > 1)
{
PointCollection ring = line.Paths[0];
MapPoint last = ring[ring.Count - 1];
for (int i = 1; i < line.Paths.Count; i++)
{
PointCollection pnts = line.Paths[i];
ring.Add(new MapPoint(180 * Math.Sign(last.X), 90 * Math.Sign(center.Y)));
last = pnts[0];
ring.Add(new MapPoint(180 * Math.Sign(last.X), 90 * Math.Sign(center.Y)));
foreach (MapPoint p in pnts)
ring.Add(p);
last = pnts[pnts.Count - 1];
}
poly.Rings.Add(ring);
//pnts.Add(first);
}
else
{
poly.Rings.Add(line.Paths[0]);
}
if (distKM > EarthRadius * Math.PI / 2 && line.Paths.Count != 2)
{
PointCollection pnts = new PointCollection();
pnts.Add(new MapPoint(-180, -90));
pnts.Add(new MapPoint(180, -90));
pnts.Add(new MapPoint(180, 90));
pnts.Add(new MapPoint(-180, 90));
pnts.Add(new MapPoint(-180, -90));
poly.Rings.Add(pnts); //Exterior
}
return poly;
}
/// <summary>
/// Returns a polyline with a constant distance from the center point measured on the sphere.
/// </summary>
/// <param name="center">The center.</param>
/// <param name="distKM">Radius in kilometers.</param>
// <returns></returns>
public static Polyline GetRadius(this MapPoint center, double distKM)
{
Polyline line = new Polyline();
PointCollection pnts = new PointCollection();
line.Paths.Add(pnts);
for (int i = 0; i < 360; i++)
{
//double angle = i / 180.0 * Math.PI;
MapPoint p = GetPointFromHeading(center, distKM, i);
if (pnts.Count > 0)
{
MapPoint lastPoint = pnts[pnts.Count - 1];
int sign = Math.Sign(p.X);
if (Math.Abs(p.X - lastPoint.X) > 180)
{ //We crossed the date line
double lat = LatitudeAtLongitude(lastPoint, p, sign * -180);
pnts.Add(new MapPoint(sign * -180, lat));
pnts = new PointCollection();
line.Paths.Add(pnts);
pnts.Add(new MapPoint(sign * 180, lat));
}
}
pnts.Add(p);
}
pnts.Add(line.Paths[0][0]);
return line;
} /// <summary>
/// Gets the shortest path line between two points. THe line will be following the great
/// circle described by the two points.
/// </summary>
/// <param name="start">The start point.</param>
/// <param name="end">The end point.</param>
/// <returns></returns>
public static Polyline GetGeodesicLine(this MapPoint start, MapPoint end)
{
Polyline line = new Polyline();
if (Math.Abs(end.X - start.X) <= 180) // Doesn't cross dateline
{
PointCollection pnts = GetGeodesicPoints(start, end);
line.Paths.Add(pnts);
}
else
{
double lon1 = start.X / 180 * Math.PI;
double lon2 = end.X / 180 * Math.PI;
double lat1 = start.Y / 180 * Math.PI;
double lat2 = end.Y / 180 * Math.PI;
double latA = LatitudeAtLongitude(lat1, lon1, lat2, lon2, Math.PI) / Math.PI * 180;
//double latB = LatitudeAtLongitude(lat1, lon1, lat2, lon2, -180) / Math.PI * 180; line.Paths.Add(GetGeodesicPoints(start, new MapPoint(start.X < 0 ? -180 : 180, latA)));
line.Paths.Add(GetGeodesicPoints(new MapPoint(start.X < 0 ? 180 : -180, latA), end));
}
return line; } private static PointCollection GetGeodesicPoints(MapPoint start, MapPoint end)
{
double lon1 = start.X / 180 * Math.PI;
double lon2 = end.X / 180 * Math.PI;
double lat1 = start.Y / 180 * Math.PI;
double lat2 = end.Y / 180 * Math.PI;
double dX = end.X - start.X;
int points = (int)Math.Floor(Math.Abs(dX));
dX = lon2 - lon1;
PointCollection pnts = new PointCollection();
pnts.Add(start);
for (int i = 1; i < points; i++)
{
double lon = lon1 + dX / points * i;
double lat = LatitudeAtLongitude(lat1, lon1, lat2, lon2, lon);
pnts.Add(new MapPoint(lon / Math.PI * 180, lat / Math.PI * 180));
}
pnts.Add(end);
return pnts;
} /// <summary>
/// Gets the latitude at a specific longitude for a great circle defined by p1 and p2.
/// </summary>
/// <param name="p1">The p1.</param>
/// <param name="p2">The p2.</param>
/// <param name="lon">The longitude in degrees.</param>
/// <returns></returns>
private static double LatitudeAtLongitude(MapPoint p1, MapPoint p2, double lon)
{
double lon1 = p1.X / 180 * Math.PI;
double lon2 = p2.X / 180 * Math.PI;
double lat1 = p1.Y / 180 * Math.PI;
double lat2 = p2.Y / 180 * Math.PI;
lon = lon / 180 * Math.PI;
return LatitudeAtLongitude(lat1, lon1, lat2, lon2, lon) / Math.PI * 180;
} /// <summary>
/// Gets the latitude at a specific longitude for a great circle defined by lat1,lon1 and lat2,lon2.
/// </summary>
/// <param name="lat1">The start latitude in radians.</param>
/// <param name="lon1">The start longitude in radians.</param>
/// <param name="lat2">The end latitude in radians.</param>
/// <param name="lon2">The end longitude in radians.</param>
/// <param name="lon">The longitude in radians for where the latitude is.</param>
/// <returns></returns>
private static double LatitudeAtLongitude(double lat1, double lon1, double lat2, double lon2, double lon)
{
return Math.Atan((Math.Sin(lat1) * Math.Cos(lat2) * Math.Sin(lon - lon2)
- Math.Sin(lat2) * Math.Cos(lat1) * Math.Sin(lon - lon1)) / (Math.Cos(lat1) * Math.Cos(lat2) * Math.Sin(lon1 - lon2)));
}
/// <summary>
/// Gets the true bearing at a distance from the start point towards the new point.
/// </summary>
/// <param name="start">The start point.</param>
/// <param name="end">The point to get the bearing towards.</param>
/// <param name="distanceKM">The distance in kilometers travelled between start and end.</param>
/// <returns></returns>
public static double GetTrueBearing(MapPoint start, MapPoint end, double distanceKM)
{
double d = distanceKM / EarthRadius; //Angular distance in radians
double lon1 = start.X / 180 * Math.PI;
double lat1 = start.Y / 180 * Math.PI;
double lon2 = end.X / 180 * Math.PI;
double lat2 = end.Y / 180 * Math.PI;
double tc1;
if (Math.Sin(lon2 - lon1) < 0)
tc1 = Math.Acos((Math.Sin(lat2) - Math.Sin(lat1) * Math.Cos(d)) / (Math.Sin(d) * Math.Cos(lat1)));
else
tc1 = 2 * Math.PI - Math.Acos((Math.Sin(lat2) - Math.Sin(lat1) * Math.Cos(d)) / (Math.Sin(d) * Math.Cos(lat1)));
return tc1 / Math.PI * 180;
} /// <summary>
/// Gets the point based on a start point, a heading and a distance.
/// </summary>
/// <param name="start">The start.</param>
/// <param name="distanceKM">The distance KM.</param>
/// <param name="heading">The heading.</param>
/// <returns></returns>
public static MapPoint GetPointFromHeading(MapPoint start, double distanceKM, double heading)
{
double brng = heading / 180 * Math.PI;
double lon1 = start.X / 180 * Math.PI;
double lat1 = start.Y / 180 * Math.PI;
double dR = distanceKM / 6378.137; //Angular distance in radians
double lat2 = Math.Asin(Math.Sin(lat1) * Math.Cos(dR) + Math.Cos(lat1) * Math.Sin(dR) * Math.Cos(brng));
double lon2 = lon1 + Math.Atan2(Math.Sin(brng) * Math.Sin(dR) * Math.Cos(lat1), Math.Cos(dR) - Math.Sin(lat1) * Math.Sin(lat2));
double lon = lon2 / Math.PI * 180;
double lat = lat2 / Math.PI * 180;
while (lon < -180) lon += 360;
while (lat < -90) lat += 180;
while (lon > 180) lon -= 360;
while (lat > 90) lat -= 180;
return new MapPoint(lon, lat);
}
}
}

  

GIS简单计算Helper类的更多相关文章

  1. Task的在主线程处理异常信息的Helper类

    最近使用task时候需要把异常记录日志,直接注入非单例模式的实例进入异步线程,在高并发情况下会出现一些问题. 所以需要把异常反馈给主线程 ,并且不在主线程里进行等待,研究相关资料后,自己写了一个简单的 ...

  2. [C#] 简单的 Helper 封装 -- RegularExpressionHelper

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  3. MVC中使用HTML Helper类扩展HTML控件

    文章摘自:http://www.cnblogs.com/zhangziqiu/archive/2009/03/18/1415005.html MVC在view页面,经常需要用到很多封装好的HTML控件 ...

  4. .NET中的加密算法总结(自定义加密Helper类续)

    1.1.1 摘要 相信许多人都使用过.NET提供的加密算法,而且在使用的过程我们必须了解每种加密算法的特点(对称或非对称,密钥长度和初始化向量等等).我也看到过很多人写过.NET中加密算法总结,但我发 ...

  5. BigDecimal精确计算工具类

    前言 在实际开发中,遇到例如货币,统计等商业计算的时候,一般需要采用java.math.BigDecimal类来进行精确计算.而这类操作通常都是可预知的,也就是通用的.所以,写了个工具类来方便以后的工 ...

  6. Util和Helper类

    Util和Helper Util Util类,应该是一个无状态的类,只有静态方法. 比如在获取某些类的全局实例化对象的时候可以使用. public class ParamUtil { ... publ ...

  7. VC++ 一个简单的Log类

    在软件开发中,为程序建立Log日志是很必要的,它可以记录程序运行的状态以及出错信息,方便维护和调试. 下面实现了一个简单的Log类,使用非常简单,仅供参考. // CLogHelper.h : hea ...

  8. 一点ASP.NET MVC Html.Helper类的方法

    一点ASP.NET MVC Html.Helper类 这里就只写一个Html.ActionLink()和Html.DropdownList(). Html.ActionLink()里有三个参数,第一个 ...

  9. 之前采用的是Helper类的方法重构时改用了扩展方法

    在手机端输入网址不方全,通常会将网址做成一个二维码,然后用手机扫一下就可以打开预览.我们每改一下样式,就在手机上点一下刷新或电脑上按一下F5,这在最初的时候,也不觉得有什么问题,因为拿到我手上的静态页 ...

随机推荐

  1. 【BZOJ3224】Tyvj 1728 普通平衡树 Splay

    Description 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3. 查询x数的排名(若有多个相同的数 ...

  2. LINQ to Entities 和LINQ to Objects 的区别

    本文资料来源:http://www.codeproject.com/Articles/246861/LINQ-to-Entities-Basic-Concepts-and-Features) LINQ ...

  3. 51nod算法马拉松12

    A 第K大区间 不妨考虑二分答案x,则问题转化成计算有多少个区间满足众数出现的次数>=x. 那么这个问题我们使用滑动窗口,枚举右端点,则左端点肯定单调递增,然后维护一个简单的数组就能资瓷添加元素 ...

  4. C语言中常量

    C语言中常量 不具有数据类型的常量------宏常量 宏常量定义:用一个标识符号来表示的常量,又称为符号常量. 宏定义:  #define 标识符  字符串                 ----- ...

  5. PostgreSQL新手入门

    自从MySQL被Oracle收购以后,PostgreSQL逐渐成为开源关系型数据库的首选. 本文介绍PostgreSQL的安装和基本用法,供初次使用者上手.以下内容基于Debian操作系统,其他操作系 ...

  6. 使用IE建多个会话的小技巧

    1 按F10出现菜单 2 选择文件----新建会话即可

  7. SpringMVC+Shiro权限管理

    什么是权限呢?举个简单的例子: 我有一个论坛,注册的用户分为normal用户,manager用户.对论坛的帖子的操作有这些:添加,删除,更新,查看,回复我们规定:normal用户只能:添加,查看,回复 ...

  8. Oracle 建立索引及SQL优化

    数据库索引: 索引有单列索引,复合索引之说,如果某表的某个字段有主键约束和唯一性约束,则Oracle 则会自动在相应的约束列上建议唯一索引.数据库索引主要进行提高访问速度. 建设原则: 1.索引应该经 ...

  9. ArcGIS初步 系列视频教程

    本人才疏学浅,但鉴于较少的ArcGIS10以上版本的学习视频,所以利用业余时间做了这么个业余的视频系列教程,本随笔提供在线观看地址与720P原版下载地址. 1认识ArcGIS 优酷在线地址  (优酷清 ...

  10. Linux_文件打包,压缩,解压

    一.压缩命令 文件格式:*.gz 命令:gzip 文件名 (ps:不能压缩目录,切压缩后不保留原文件) 压缩前 -rw-r--r--. 1 root root 315 Sep 6 21:03 df.t ...