Polar 投影c#版本移植
from:http://hi.baidu.com/sungaoyong/item/0c4584d25873f131e3108f05
///刘泽军java版本的极坐标投影c#版本的移植
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
namespace MyPolar
{
/// <summary>
/// 自定义的Math类,支持角度到弧度和弧度到角度的计算
/// 对应Java Math中的Math.toDegrees和Math.toRadians
/// </summary>
class CMath
{
public static Double PI = Math.PI;
static public Double toDegrees(Double rad)
{
return (rad * (180.0f / PI));
}
static public Double toRadians(Double deg)
{
return (deg * (PI / 180.0f));
}
public static double cos(double d)
{
return Math.Cos(d);
}
public static double acos(double d)
{
return Math.Acos(d);
}
public static double sin(double d)
{
return Math.Sin(d);
}
public static double abs(double d)
{
return Math.Abs(d);
}
public static double IEEERemainder(double x, double y)
{
return Math.IEEERemainder(x, y);
}
public static double sqrt(double d)
{
return Math.Sqrt(d);
}
public static double atan(double d)
{
return Math.Atan(d);
}
}
/*
Polar 投影(扫描方式,自正北方向顺时针)
PACKAGE: cma.common.projection
FILENAME: Polar.java
LANGUAGE: Java2 v1.4
ORIGINAL: 无
DESCRIPTION: 极坐标投影(主要用于雷达图像处理)
RELATED: cma.common.projection.Lambert(兰勃特投影)
EDITOR: UltraEdit-32 v12.20a(Windows) NEdit(Linux)
CREATE: 2007-05-06 20:08:23
UPDATE: 2007-07-18 修改为抽象类Coordinate的扩展类
AUTHOR: 刘泽军 ()
广西气象减灾研究所
Guangxi Institude of Meteorology and Disaster-reducing Research(GIMDR)
Compile : javac Coordinate.java Polar.java
How to use Polar class:
Polar polar = new Polar(109.24, 24.35, 512, 384, 1.0, 0.0);//构造函数
...
孙高勇2011-02-10移植到DotNet版本。
*/
/**
*
* 扫描平面
* /
* /
* /
* /
* /
* / 仰角
* -------------------- 0度平面
*
* 如图所示:
* 扫描平面=>0度平面,需要乘以cos(仰角)
* 0度平面=>扫描平面,需要除以cos(仰角)
*
* 注意,日常显示的雷达图是扫描平面上的图。本类所说的屏幕指扫描平面。
*
*/
/**
* 雷达扫描示意图
*
* 359 0
* | radius
* | /
* | /
* |angle/
* | /
* | ^ /
* | /
* | /
* |/
* 270 -----------------中心----------------- 90
* |
* |
* |
* |
* |
* |
* |
* |
* |
* 180
*/
class Polar
{
//静态常量,地球半径,来源:《大气科学常用公式》,P601,附录
public static double RADIUS = 6371.004;//地球平均半径,单位:公里(Km)。
public static double RADIUS_POLAR = 6356.755;//地球两极半径,单位:公里(Km)。
public static double RADIUS_EQUATOR = 6373.140;//地球赤道半径,单位:公里(Km)。
//私有成员
private PointF center; //中心对应的屏幕位置
private Point place; //中心经纬度对应的屏幕坐标
private Point offset; //偏移量
//缩放系数
private double scale;
private double scaleOriginal;
//private double centerLongitude = 0.0; //中心经度
//private double centerLatitude = 0.0; //中心纬度
private double perKilometer = 1.0; //比例尺:一公里对应的像素点数(扫描平面)
private double elevation = 0.0; //仰角
private double cosineElevation = 1.0; //仰角的余弦值
private double kmPerDegreeX = 1.0; //1经度对应的距离(公里),不同纬度数值不同
private double kmPerDegreeY = 1.0; //1纬度对应的距离(公里),不同纬度数值不同
/**
* 功能:计算球面上两点间的距离(单位:公里),原在edu.gimdr.Atmos.Meteorology类中写有,为避免import过多的类,故重写一份
* 参数:
* lon1,lat1 - 第1点的位置(经纬度)
* lon2,lat2 - 第2点的位置(经纬度)
* 返回值:
* 球面距离
*/
public static double distanceOfSphere(double lon1, double lat1, double lon2, double lat2)
{
/* 公式:
A(x,y) B(a,b)
AB点的球面距离=R*{arccos[cos(b)*cos(y)*cos(a-x)+sin(b)*sin(y)]}, by Google
*/
double rlon1 = CMath.toRadians(lon1);
double rlat1 = CMath.toRadians(lat1);
double rlon2 = CMath.toRadians(lon2);
double rlat2 = CMath.toRadians(lat2);
return (RADIUS * (CMath.acos(CMath.cos(rlat2) * CMath.cos(rlat1) * CMath.cos(rlon2 - rlon1) + CMath.sin(rlat2) * CMath.sin(rlat1))));
}
/**
* 功能:
* 重置参数
* 参数:
* lon,lat - 中心经纬度,
* px,py - 中心经纬度对应的屏幕坐标
* sc - 缩放系数
* agl - 仰角
* 返回值:
* 无
*/
public void reset(double lon, double lat, int px, int py, double sc, double agl)
{
//type = POLAR;
center = new PointF(
(float)(lon < 0.0 ? 0.0 : lon > 360.0 ? 360.0 : lon),
(float)(lat < -90.0 ? -90.0 : lat > 90.0 ? 90.0 : lat)
);
place = new Point(px, py);
elevation = CMath.toRadians(CMath.IEEERemainder(CMath.abs(agl), 90.0));//在0-90度之间,但不能为90度
cosineElevation = CMath.cos(elevation);//仰角的余弦值
scale = sc == 0.0 ? 1.0 : CMath.abs(sc);//缩放系数
scaleOriginal = scale;
offset = new Point(0, 0);
perKilometer = 1.0;//标准比例尺
////中心经纬度或仰角发生改变,必须重新计算经向和纬向的1度对应的球面距离
kmPerDegreeX = distanceOfSphere(center.X, center.Y, center.X + 1.0, center.Y) / cosineElevation;
kmPerDegreeY = distanceOfSphere(center.X, center.Y, center.X, center.Y + 1.0) / cosineElevation;
}
/**
* 功能:构造函数
* 参数:
* lon - 中心对应的经度坐标
* lat - 中心对应的纬度坐标
* x - 中心对应的屏幕位置x
* y - 中心对应的屏幕位置y
* sc - 缩放系数
* 返回值:
* 无
*/
public Polar(double lon, double lat, int x, int y, double sc)
{
reset(lon, lat, x, y, sc, 0.0);
}
/**
* 功能:构造函数
* 参数:
* lon - 中心对应的经度坐标
* lat - 中心对应的纬度坐标
* x - 中心对应的屏幕位置x
* y - 中心对应的屏幕位置y
* sc - 缩放系数
* agl = 仰角
* 返回值:
* 无
*/
public Polar(double lon, double lat, int x, int y, double sc, double agl)
{
reset(lon, lat, x, y, sc, agl);
}
/**
* 功能:获得仰角
* 参数:
* 无
* 返回值:
* 仰角的度数
*/
public double getElevation()
{
return (CMath.toDegrees(elevation));
}
/**
* 功能:获得经纬度对应的屏幕像素坐标,与雷达仰角有关,主要用于体扫数据显示、底图叠加等。
* 参数:
* lon - 经度
* lat - 纬度
* 返回值:
* 对应的屏幕坐标
*/
public Point getPosition(double lon, double lat)
{
double disX = distanceOfSphere(lon, center.Y, center.X, center.Y) / cosineElevation;
double disY = distanceOfSphere(center.X, lat, center.X, center.Y) / cosineElevation;
double x = (lon > center.X ? 1 : -1) * (disX * perKilometer * scale) + place.X + 0.5;
double y = -(lat > center.Y ? 1 : -1) * (disY * perKilometer * scale) + place.Y + 0.5;
return (new Point((int)x, (int)y));
}
/**
* 功能:获得极坐标对应的屏幕像素坐标,与雷达仰角无关,主要用于体扫数据显示、底图叠加等。
* 参数:
* radius - 极半径
* angle - 角度(以正北方向顺时针)
* 返回值:
* 对应的屏幕坐标
*/
public Point getXY(double radius, double angle)
{
int x = (int)(0.5 + radius * CMath.sin(CMath.toRadians(angle)));
int y = (int)(0.5 + radius * CMath.cos(CMath.toRadians(angle)));
return (new Point(place.X + x, place.Y - y));
}
/**
* 功能:获得屏幕像素点位置的极坐标半径,由于是输入参数是扫描平面上的值,故与雷达仰角无关。
* 参数:
* x - 水平坐标
* y - 垂直坐标
* 返回值:
* 与极坐标中心的距离,即极半径
*/
public double getRadius(int x, int y)
{
return (CMath.sqrt(1.0 * (x - place.X) * (x - place.X) + 1.0 * (y - place.Y) * (y - place.Y)));
}
/**
* 功能:获得经纬度位置的极坐标半径,与雷达仰角有关。
* 参数:
* lon - 经度坐标
* lat - 纬度坐标
* 返回值:
* 与极坐标中心的距离(象素点),即极半径
*/
public double getRadius(double lon, double lat)
{
Point pos = getPosition(lon, lat);//此函数已经考虑了仰角的影响
return (getRadius(pos.X, pos.Y));
}
/**
* 功能:获得屏幕像素点位置的极坐标角度(扫描平面与0度平面均相同),与雷达仰角无关。
* 参数:
* x - 水平坐标
* y - 垂直坐标
* 返回值:
* 角度值,自正北方向顺时针
*/
public double getAngle(int x, int y)
{
double agl = 0.0;
if (x == place.X && y == place.Y)
{
//重合
agl = 0.0;
}
else if (x == place.X)
{
agl = y > place.Y ? 180.0 : 360.0;
}
else if (y == place.Y)
{
agl = x > place.X ? 90.0 : 270.0;
}
else
{
agl = CMath.toDegrees(CMath.atan(1.0 * CMath.abs(x - place.X) / CMath.abs(y - place.Y)));
agl =
x > place.X && y < place.Y ? agl : //直角坐标的第一象限
x < place.X && y < place.Y ? 180.0 - agl : //直角坐标的第二象限
x < place.X && y > place.Y ? 180.0 + agl : //直角坐标的第三象限
x > place.X && y > place.Y ? 360.0 - agl : //直角坐标的第四象限
agl;
}
//System.out.println(agl);
return (agl);
}
/**
* 功能:获得经纬度位置的极坐标角度(扫描平面与0度平面均相同),与雷达仰角无关。
* 参数:
* lon - 水平坐标
* lat - 垂直坐标
* 返回值:
* 角度值,自正北方向顺时针
*/
public double getAngle(double lon, double lat)
{
/*
//若通过获得屏幕坐标来计算角度,精度比较差,特别是在极坐标中心附近
Point p = getPosition(lon, lat);
return(getAngle(p.x, p.y);
*/
double agl = 0.0;
if( lon == center.X && lat == center.Y) //重合
{
agl = 0.0;
}
else if( lon == center.X )
{
agl = lat > center.Y ? 360.0 : 180.0;
}
else if( lat == center.Y )
{
agl = lon > center.X ? 90.0 : 270.0;
}
else
{
//注:由于经向和纬向的球面距离不等(华南,经向>纬向),故点(1,1)与中心点(0,0)的极角不等45度,而应是略大于45度
agl = CMath.toDegrees(CMath.atan((CMath.abs(lon-center.X)*kmPerDegreeX)/(CMath.abs(lat-center.Y)*kmPerDegreeY)));
agl =
lon > center.X && lat > center.Y ? agl : //第一象限
lon < center.X && lat > center.Y ? 180.0 - agl : //第二象限
lon < center.X && lat < center.Y ? 180.0 + agl : //第三象限
lon > center.X && lat < center.Y ? 360.0 - agl : //第四象限
agl;
}
return(agl);
}
/**
* 功能:
* 获得屏幕坐标对应的经纬度
* 参数:
* x - 屏幕水平坐标
* y - 屏幕垂直坐标
* 返回值:
* 对应的经纬度
*/
public PointF getCoordinate(int x, int y)
{
/*
目标点 A(X,Y) 弧度
中心点 B(A,B) 弧度
AB球面距离=R*{arccos[cos(B)*cos(Y)*cos(A- X)+sin(B)*sin(Y)]}, by Google
经度相同 =& gt; AB = R*{arccos[cos(B)*cos(Y)+sin(B)*sin(Y)]}
=> AB = R*{arccos[cos(B-Y)]}
=> AB = R * (B-Y)
=> AB / R = B - Y
=> Y = B - AB /R
=> Y = B - (y-centerPosition.y)*cosineElevation/perKilometer/scale/R
*/
double lat = CMath.toDegrees(CMath.toRadians(center.Y) + (place.Y-y)*cosineElevation/perKilometer/scale/Polar.RADIUS);
double disX0 = distanceOfSphere(center.X, lat, center.X+1.0, lat);//0度平面上1经度的球面距离
double disX = disX0 / cosineElevation; //扫描平面上1经度的距离
double perDegreeX = disX * perKilometer * scale; //扫描平面上1经度的对应的像素点数
double lon = center.X + (x - place.X) / perDegreeX;
return (new PointF((float)lon, (float)lat));
}
/**
* 功能:
* 获得四角坐标对应的经纬度
* 参数:
* W - 图像高度
* H - 图像宽度
* 返回值:
* 对应的经纬度
* add by sungaoyong 2011-02-10
*/
public PointF[] getRecF(Double W, double H)
{
PointF PointLeftTop = getCoordinate((int)(0.5 + place.X - scale * W / 2), (int)(0.5 + place.Y - scale * H / 2));
PointF PointRightTop = getCoordinate((int)(0.5 + place.X + scale * W /2), (int)(0.5 + place.Y - scale * H / 2));
PointF PointLeftBottom = getCoordinate((int)(0.5 + place.X - scale * W / 2), (int)(0.5 + place.Y + scale * H / 2));
PointF PointRightBottom = getCoordinate((int)(0.5 + place.X + scale * W / 2), (int)(0.5 + place.Y + scale * H / 2));
return (new PointF[] { PointLeftTop, PointRightTop, PointLeftBottom, PointRightBottom });
}
/**
* 功能:
* 画经线、纬线
* 参数:
* g - 图形设备
* f - 字体
* c - 画线颜色
* inc_lon - 经线间隔//未使用
* inc_lat - 纬线间隔//未使用
* 返回值:
* 无
*/
public void drawGridLine(System.Drawing.Graphics g, Font f, Color c, int inc_lon, int inc_lat)
{
//Color saveColor = g.getColor();
//Font saveFont = g.getFont();
Pen blue = new Pen(Color.Blue);
//以下两行改进线条的锯齿
//RenderingHints renderHints = new RenderingHints(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
//g.setRenderingHints(renderHints);
// g.setColor(Color.black);//背景色
// g.fillRect(c.x-(int)(z*240), c.y-(int)(z*240), (int)(z*240*2), (int)(z*240*2));
//g.setColor(c);//雷达图形区域的边框颜色
g.DrawArc(blue,new RectangleF((int)(0.5+place.X-scale*240), (int)(0.5+place.Y-scale*240), (int)(0.5+scale*240*2), (int)(0.5+scale*240*2)),0,0);
//画极径
Point pos1, pos2;
for(double i=0.0; i<180.0; i=i+30.0)
{
pos1 = getXY(scale*240.0, 0.0+i);
pos2 = getXY(scale*240.0, 180.0+i);
g.DrawLine(blue,pos1.X, pos1.Y, pos2.X, pos2.Y);
}
//画极圈
for(int i=50; i<=200; i=i+50) //每50公里画一个圈
{
g.DrawArc(blue,new RectangleF((int)(0.5+place.X-scale*i), (int)(0.5+place.Y-scale*i), (int)(0.5+scale*i*2), (int)(0.5+scale*i*2)), 0, 360);
}
g.DrawArc(blue,new RectangleF((int)(0.5 + place.X - scale * 240), (int)(0.5 + place.Y - scale * 240), (int)(0.5 + scale * 240 * 2), (int)(0.5 + scale * 240 * 2)), 0, 360);//外圈240公里
//g.setFont(saveFont);
//g.setColor(saveColor);
}
}
}
Polar 投影c#版本移植的更多相关文章
- cocos2dx android版本移植时的Error format not a string literal and no format arguments解决方案
原文地址 : http://www.cnblogs.com/hhuang2012/p/3336911.html cocos2dx android版本移植时的Error format not a str ...
- LEDAPS1.3.0版本移植到windows平台----HuSr大气校正模块
这个是2012年左右放在百度空间的,谁知百度空间关闭...转移到博客园. 最近项目用到3.1.2版本的LEDAPS,新版本的使用情况会在后续文章中慢慢丰富. HuSr是将LEDAPS项目中的TM/ET ...
- 低版本GCC程序向高版本移植的兼容性问题
将低版本gcc编译过的程序移植到高版本GCC时, 可能会出现一些兼容性问题. 原因是, 为了适应新的标准,一些旧的语法规则被废弃了. 关于这方面的一些具体资料可从该处查询. 这里只是自己遇到的其中一个 ...
- LEDAPS1.3.0版本移植到windows平台----HuPm参数初始化模块
这个是2012年左右放在百度空间的,谁知百度空间关闭...转移到博客园. 最近项目用到3.1.2版本的LEDAPS,新版本的使用情况会在后续文章中慢慢丰富. LEDAPS的调用顺序是:HuPm--&g ...
- LEDAPS1.3.0版本移植到windows平台----HuCsm云掩膜模块
这个是2012年左右放在百度空间的,谁知百度空间关闭...转移到博客园. 最近项目用到3.1.2版本的LEDAPS,新版本的使用情况会在后续文章中慢慢丰富. HuCsm是将LEDAPS项目中的TM/E ...
- LEDAPS1.3.0版本移植到windows平台----HuCal定标模块
这个是2012年左右放在百度空间的,谁知百度空间关闭...转移到博客园. 最近项目用到3.1.2版本的LEDAPS,新版本的使用情况会在后续文章中慢慢丰富. HuCal是将LEDAPS项目中的TM/E ...
- jz2440-uboot-201204版本移植【学习笔记】【原创】
平台:jz2440 作者:庄泽彬(欢迎转载,请注明作者) 说明:韦东山二期视频学习笔记 交叉编译工具:arm-linux-gcc (GCC)4.3.2 PC环境:ubuntu18.04 一.uboot ...
- iperf linux版本移植到android (使用工具链方式不是使用Android.mk)
由于很多程序是用makefile编译linux应用程序的,如果移植到android就要重新写Android.mk,对于不熟悉这个的人来说,特别麻烦,所以这里介绍只修改makefile就能移植到andr ...
- 安利一个IDA插件diaphora,可以将函数名、注释、结构体等的先前版本移植到新版本
插件代码地址 https://github.com/joxeankoret/diaphora 使用方法: 启动IDA并首先打开包含完整符号的二进制文件1.让我们的IDA完成初始的自动分析,之后,通过运 ...
随机推荐
- AudioToolKit的简单介绍及教程
AudioToolKit的简单介绍及教程 (2013-02-21 09:29:18) 转载▼ 标签: 游戏开发 unity3d教程 unity3d unity it 分类: Unity3d之插件篇 原 ...
- 返回当前文档的文档的url
HTML DOM referrer 属性 HTML DOM Document 对象 定义和用法 referrer 属性可返回载入当前文档的文档的 URL. 语法 document.referrer 说 ...
- Jetty锁定文件的问题
在windows系统上,jetty默认在运行时会锁定部署的文件.这对于需要在程序运行期间动态生成或改动某些文件就变得不能执行!对于这一点,Jetty的官网上专门有文章进行了解释:http://docs ...
- SpringMVC学习(一)小demo
首先看一下整个demo的项目结构: 第一步是导入Spring MVC单独使用时的最少jar包: 第二步在项目的web.xml中配置Spring MVC提供的拦截请求的Servlet: 全类名是:org ...
- Python 安装 MaxMind GeoLite City
1.先安装 geoip c library geoip c library >= 1.4.6 installed on your machine. >= 1.4.6 installed ...
- 第一百八十九节,jQueryUI,折叠菜单 UI
jQueryUI,折叠菜单 UI 学习要点: 1.使用 accordion 2.修改 accordion 样式 3.accordion()方法的属性 4.accordion()方法的事件 5.acco ...
- python django -6 常用的第三方包或工具
常用的第三方包或工具 富文本编辑器 缓存 全文检索 celery 布署 富文本编辑器 借助富文本编辑器,管理员能够编辑出来一个包含html的页面,从而页面的显示效果,可以由管理员定义,而不用完全依赖于 ...
- PostgreSQL tips
tip 1 在sql中我们可以设置一个列自增长identity(1,1),但在postgresql中却没有这个关键字定义.但postgresql也有实现相关功能,那就是只需要将该列数据类型标记为ser ...
- SQL Server 还原错误“restore database正在异常终止 错误 3154”
今天在还原数据库时,先建立相同名字的数据库,然后在该数据库上右键还原数据库.遇到了这样的一个错误: “备份集中的数据库备份与现有的 'RM_DB' 数据库不同. RESTORE DATABASE 正在 ...
- js 日期加一天
经常在js 重要做时间加一的处理记录一下 ps:时间格式为:'2017-03-30' 一:源码: //时间加一天 function addDate(date, days) { if (days == ...