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#版本移植的更多相关文章

  1. 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 ...

  2. LEDAPS1.3.0版本移植到windows平台----HuSr大气校正模块

    这个是2012年左右放在百度空间的,谁知百度空间关闭...转移到博客园. 最近项目用到3.1.2版本的LEDAPS,新版本的使用情况会在后续文章中慢慢丰富. HuSr是将LEDAPS项目中的TM/ET ...

  3. 低版本GCC程序向高版本移植的兼容性问题

    将低版本gcc编译过的程序移植到高版本GCC时, 可能会出现一些兼容性问题. 原因是, 为了适应新的标准,一些旧的语法规则被废弃了. 关于这方面的一些具体资料可从该处查询. 这里只是自己遇到的其中一个 ...

  4. LEDAPS1.3.0版本移植到windows平台----HuPm参数初始化模块

    这个是2012年左右放在百度空间的,谁知百度空间关闭...转移到博客园. 最近项目用到3.1.2版本的LEDAPS,新版本的使用情况会在后续文章中慢慢丰富. LEDAPS的调用顺序是:HuPm--&g ...

  5. LEDAPS1.3.0版本移植到windows平台----HuCsm云掩膜模块

    这个是2012年左右放在百度空间的,谁知百度空间关闭...转移到博客园. 最近项目用到3.1.2版本的LEDAPS,新版本的使用情况会在后续文章中慢慢丰富. HuCsm是将LEDAPS项目中的TM/E ...

  6. LEDAPS1.3.0版本移植到windows平台----HuCal定标模块

    这个是2012年左右放在百度空间的,谁知百度空间关闭...转移到博客园. 最近项目用到3.1.2版本的LEDAPS,新版本的使用情况会在后续文章中慢慢丰富. HuCal是将LEDAPS项目中的TM/E ...

  7. jz2440-uboot-201204版本移植【学习笔记】【原创】

    平台:jz2440 作者:庄泽彬(欢迎转载,请注明作者) 说明:韦东山二期视频学习笔记 交叉编译工具:arm-linux-gcc (GCC)4.3.2 PC环境:ubuntu18.04 一.uboot ...

  8. iperf linux版本移植到android (使用工具链方式不是使用Android.mk)

    由于很多程序是用makefile编译linux应用程序的,如果移植到android就要重新写Android.mk,对于不熟悉这个的人来说,特别麻烦,所以这里介绍只修改makefile就能移植到andr ...

  9. 安利一个IDA插件diaphora,可以将函数名、注释、结构体等的先前版本移植到新版本

    插件代码地址 https://github.com/joxeankoret/diaphora 使用方法: 启动IDA并首先打开包含完整符号的二进制文件1.让我们的IDA完成初始的自动分析,之后,通过运 ...

随机推荐

  1. strex,ldrex

    volatile bool lock = false; void func(void) { int i; while(lock);   lock = true; for(i = 0; i < 4 ...

  2. codeforces #363a Launch of Collider

    A. Launch of Collider time limit per test 2 seconds memory limit per test 256 megabytes input standa ...

  3. 设计模式中类的关系之关联关系(Association)

    关联关系是类与类之间最常用的一种关系,它是一种结构化关系,用于表示一类对象与另一类对象之间有联系.它体现的是两个类.或者类与接口之间语义级别的一种强依赖关系,比如我和我的朋友.这种关系比依赖更强.不存 ...

  4. 基于springCloud的分布式架构体系

    Spring Cloud作为一套微服务治理的框架,几乎考虑到了微服务治理的方方面面,之前也写过一些关于Spring Cloud文章,主要偏重各组件的使用,本次分享主要解答这两个问题:Spring Cl ...

  5. php 批量处理post数据

    <?php header("Content-Type:text/html;charset=UTF-8"); include('ini.php'); foreach ($_PO ...

  6. Tensorflow如何选择GPU

    CUDA_VISIBLE_DEVICES=1 python run.py or import os os.environ["CUDA_VISIBLE_DEVICES"]=" ...

  7. Eclipse 添加书签

    Eclipse 添加书签 关于书签 Eclipse 中可以在编辑器的任意一行添加书签. 您可以使用书签作为提示信息,或者使用书签快速定位到文件中的指定的行. 添加书签 如果你想设置书签,你只需要在垂直 ...

  8. js array filter pop push shift unshift方法

    JavaScript Array filter() 方法  JavaScript Array 对象 实例 返回数组 ages 中所有元素都大于 18 的元素: var ages = [32, 33,  ...

  9. 非常实用的JavaScript小技巧

    使用!!操作符转换布尔值 有时候我们需要对一个变量查检其是否存在或者检查值是否有一个有效值,如果存在就返回true值.为了做这样的验证,我们可以使用!!操作符来实现是非常的方便与简单.对于变量可以使用 ...

  10. Laravel开发:Laravel核心——Ioc服务容器源码解析(服务器解析)

    make解析 服务容器对对象的自动解析是服务容器的核心功能,make 函数.build 函数是实例化对象重要的核心,先大致看一下代码: public function make($abstract) ...