天气雷达的基本要素有很多,特别是双偏振雷达更多,但业务场景经常使用的一般为基本反射率,基本速度这两种要素

接下来我们以基本反射率为例,其他的要素也是一样的,一通百通

首先我们做基本反射率的图需要确定做哪一个仰角层,因为雷达体扫模式的扫描是不同仰角进行扫描的,常规的雷达一般是9个仰角

按照上图就很明显的知道体扫模式的扫描是怎样的情况了

由于雷达基本的要素都是径向数据,我们先以图的方式看径向数据如何绘制

可以看到,要素产品是由n条径向数据组成,所有的径向数据从O点根据方位角以及距离,正好形成一个完美的圆

所以我们画一层仰角的图就需要距离,方位角,数值即可

现在我们就画基本反射率第一层的径向数据图,也就是0.5度仰角

MeteoDataInfo meteoDataInfo = new MeteoDataInfo();
meteoDataInfo.openData("D:\\tls\\Z_RADR_I_站点_20220407233130_O_DOR_CC_CAP_FMT.bin");
CMARadarBaseDataInfo info = (CMARadarBaseDataInfo) meteoDataInfo.getDataInfo();
//色阶颜色
int[][] cols = {
{255, 255, 255},
{102, 255, 255},
{102, 255, 255},
{0, 162, 232},
{86, 225, 250},
{3, 207, 14},
{26, 152, 7},
{255, 242, 0},
{217, 172, 113},
{255, 147, 74},
{255, 0, 0},
{204, 0, 0},
{155, 0, 0},
{236, 21, 236},
{130, 11, 130},
{184, 108, 208}
};
//色阶数值
double[] levs = new double[]{Integer.MIN_VALUE,0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70,Integer.MAX_VALUE};
//根据RGB返回Color对象
Color[] colors = ColorUtil.getColorsFromStyle(cols);
//根据数值和颜色生成绘图所用的色阶
LegendScheme ls = LegendManage.createGraduatedLegendScheme(levs,colors, ShapeTypes.POLYGON);
List<String> list = new ArrayList<>();
//提前准备好所需要的要素
//反射率
list.add("dBZ");
//方位角
list.add("azimuthR");
//距离
list.add("distanceR");
//仰角
list.add("elevationR");
//从基数据中取出对应数据绘制成图层
VectorLayer layer = MeteoinfoUtil.getRadarArray(info,list,0,ls);
MapView view = new MapView();
view.addLayer(layer);
//导出图片
MeteoinfoUtil.export(view,1200,"D:/tls/r.png");
ColorUtil.getColorsFromStyle这个方法很简单,我随便封装了一下,只是为了满足根据RGB返回Color对象,所以代码就不公布了
而MeteoinfoUtil.getRadarArray是取值的核心,我们来具体讲解一下
public static VectorLayer getRadarArray(CMARadarBaseDataInfo info, List<String> pros, int i, LegendScheme ls) throws Exception {
//站点纬度
Attribute lat = info.findGlobalAttribute("StationLatitude");
//站点经度
Attribute lon = info.findGlobalAttribute("StationLongitude");
//海拔高度
Attribute high = info.findGlobalAttribute("AntennaHeight");
List<String> names = info.getVariableNames();
if (!names.containsAll(pros)) {
return null;
}
//从基数据中读取所需要素的径向数据
Array ay = info.read(pros.get(0));
Array[] arrays = new Array[4];
//获取径向数据的条数,也就是方位角个数
int azimuthNum = ay.getShape()[1];
//获取一条径向数据的数据块个数
int dataBlockNum = ay.getShape()[2];
//---------获取i层的径向数据,格式布局为Z*Y*X
//设定读取数据的起始位置
int[] origin = new int[]{i, 0, 0};
//设定所读取数据数量
int[] size = new int[]{1, azimuthNum, dataBlockNum};
//设定读取数据的步幅
int[] stride = new int[]{1, 1, 1};
//取出要素的单层径向数据
arrays[0] = info.read(pros.get(0), origin, size, stride);
//---------获取i层的方位角
origin = new int[]{i, 0};
size = new int[]{1, azimuthNum};
stride = new int[]{1, 1};
//取出单层的方位角
arrays[1] = info.read(pros.get(1), origin, size, stride);
//-----------获取i层数据块的距离
origin = new int[]{0};
size = new int[]{dataBlockNum};
stride = new int[]{1};
arrays[2] = info.read(pros.get(2), origin, size, stride);
//------------获取i层的仰角数据
origin = new int[]{i, 0};
size = new int[]{1, azimuthNum};
stride = new int[]{1, 1};
arrays[3] = info.read(pros.get(3), origin, size, stride);
//------------获取所需数据end--------------
//将方位角和仰角从角度转化为弧度
Array azi = ArrayMath.toRadians(arrays[1]);
Array ele = ArrayMath.toRadians(arrays[3]);
//使用距离和方位角(弧度)创建二维矩阵,这一步更重要的是为了适用Transform.antennaToCartesian
Array[] a = ArrayUtil.meshgrid(arrays[2], azi);
Array dis = a[0];
azi = a[1];
List<Integer> list = new ArrayList<Integer>();
list.add(dis.getShape()[1]);
重组对象格式
ele = ele.reshape(new int[]{azimuthNum, 1});
//塞数据进去
ele = ArrayUtil.repeat(ele, list, 1);
int h = Integer.parseInt(high.getValue().toString().trim());
//天线坐标转换为笛卡尔坐标
Array[] aa = Transform.antennaToCartesian(dis, azi, ele, h);
String projection = String.format("+proj=aeqd +lon_0=%s +lat_0=%s",
Double.parseDouble(lon.getValue().toString().trim()),
Double.parseDouble(lat.getValue().toString().trim()));
//确定投影,方便后续加地图或地理信息
ProjectionInfo projectionInfo = factory(new CRSFactory().createFromParameters("custom",
projection));
//坐标重投影
Array[] xy = Reproject.reproject(aa[0], aa[1], projectionInfo, LONG_LAT);
//绘制图层
VectorLayer layer = DrawMeteoData.meshLayer(xy[0], xy[1], arrays[0], ls);
return layer;
}

这种方法是最复杂也是速度较慢的,但同时也是不会丢任何数据的方法,下一节我们换种使用了插值法的绘制方法,使用了插值后,性能以及速度就得到了大大的提升  

MeteoInfo-Java解析与绘图教程(十)_JAVA绘制雷达PPI图的更多相关文章

  1. MeteoInfo-Java解析与绘图教程(八)_java解析卫星FY-4A一级产品文件(HDF举例)

    MeteoInfo-Java解析与绘图教程(八)_java解析卫星一级产品文件(HDF举例) 最近解析卫星数据遇到了一级产品,它的解析方式与之前文章说的有些不同,特此补充一下 卫星的一级产品,里面是没 ...

  2. MeteoInfo-Java解析与绘图教程(一)

    MeteoInfo-Java解析与绘图教程(一) 已经进入开发行业很多年了,这两年一直从事气象开发行业,为此对气象绘图有了新的见解 像色斑图与卫星图一直都有python去绘制,在偶然的情况下,我接触到 ...

  3. MeteoInfo-Java解析与绘图教程(三)

    MeteoInfo-Java解析与绘图教程(三) 上文我们说到简单绘制色斑图(卫星云图),但那种效果可定不符合要求,一般来说,客户需要的是在地图上色斑图的叠加,或者是将图片导出分别是这两种效果 当然还 ...

  4. MeteoInfo-Java解析与绘图教程(四)

    MeteoInfo-Java解析与绘图教程(四) 上文我们说到,将地图叠加在色斑图上,但大部分都是卫星绘图,现在开始讲解micaps数据绘图,同样也是更多自定义配置 首先我们解析micaps数据,将之 ...

  5. MeteoInfo-Java解析与绘图教程(五)

    MeteoInfo-Java解析与绘图教程(五) 最近太忙了,终于有时间继续写了,上文说到了基本上的绘图方法,但缺少色阶呈现,一般图叠加着地图上,后端不需要管色阶,但也要注意web页面色阶和我们的生成 ...

  6. MeteoInfo-Java解析与绘图教程(七)_图层添加站点名称或区域名称

    MeteoInfo-Java解析与绘图教程(七)_图层添加站点名称或区域名称 在上文说了用自动站的数据经过插值绘制色斑图,这种一般是在geoserver上叠加图片呈现,但遇到后端导出图片,我们又想添加 ...

  7. Java Web快速入门——全十讲

    Java Web快速入门——全十讲 这是一次培训的讲义,就是我在给学生讲的过程中记录下来的,非常完整,原来发表在Blog上,我感觉这里的学生可能更需要. 内容比较长,你可以先收藏起来,慢慢看. 第一讲 ...

  8. Android为TV端助力 转载:Android绘图Canvas十八般武器之Shader详解及实战篇(上)

    前言 Android中绘图离不开的就是Canvas了,Canvas是一个庞大的知识体系,有Java层的,也有jni层深入到Framework.Canvas有许多的知识内容,构建了一个武器库一般,所谓十 ...

  9. [转]Android自定义控件三部曲系列完全解析(动画, 绘图, 自定义View)

    来源:http://blog.csdn.net/harvic880925/article/details/50995268 一.自定义控件三部曲之动画篇 1.<自定义控件三部曲之动画篇(一)—— ...

  10. atitit.java解析sql语言解析器解释器的实现

    atitit.java解析sql语言解析器解释器的实现 1. 解析sql的本质:实现一个4gl dsl编程语言的编译器 1 2. 解析sql的主要的流程,词法分析,而后进行语法分析,语义分析,构建sq ...

随机推荐

  1. 关于 CLOI 头像&博客主题征集

    是这样的,开了一个新号准备做一个官号,当作一个公告栏(?),大家访问博客或者看消息也方便 现在苦于脑袋比较笨,想不出头像来,有意者可以帮设计下 此外,还(选择性地)需要一个博客主题,主要是简洁,打开会 ...

  2. 如何判断一个网站是用的Nginx,还是Apache

    事件起因: 接手了同事移交过来的一个网站,但是不知道这个网站是用什么做代理的,于是就去网上查资料   解决办法: 打开cmd窗口,输入以下命令即可 curl --head 域名/IP 注意,--hea ...

  3. 【赵渝强老师】在Hive中使用Load语句加载数据

    一.Hive中load语句的语法说明 Hive Load语句不会在加载数据的时候做任何转换工作,而是纯粹的把数据文件复制/移动到Hive表对应的地址.语法格式如下: LOAD DATA [LOCAL] ...

  4. C++的并发编程历史

    多线程环境 并非所有的语言都提供了多线程的环境.即便是C++语言,直到C++11标准之前,也是没有多线程支持的. 在这种情况下,Linux/Unix平台下的开发者通常会使用POSIX Threads, ...

  5. CF753B题解

    这应该算是一个很脍炙人口的小游戏了吧 (没玩过算我没说) 因为一共有 \(50\) 次询问机会,那最简单直接的方法就不难想到. 我们把 \(0 \sim9\) 全部询问一遍,如果回答两个整数不全为 \ ...

  6. python中利用变量解压列表、元组、字符串、字典、文件对象、迭代器和生成器等序列

    一.如果知道序列中元素的个数,可以直接进行变量赋值. coords = (102, 40) lon, lat = coords print(lon) print(lat) text = "n ...

  7. 用sdkman管理多个jdk切换

    前言 最近项目前后端进行升级,需要在jdk8和jdk17两个版本切换.最简单的是通过手动切换,但切换过程太繁琐,修改环境变量,达到切换目的.于是尝试其它解决方案,最终确实使用sdkman工具. sdk ...

  8. EBS GL 当前职责有访问权限的所有账套

    CREATE OR REPLACE VIEW CUX_GL_ACCESS_LEDGER_V AS SELECT L.LEDGER_ID,L.NAME,L.LEDGER_CATEGORY_CODE FR ...

  9. CNI 基准测试:Cilium 网络性能分析

    原文链接:https://cilium.io/blog/2021/05/11/cni-benchmark 作者:Thomas Graf 译者:罗煜.张亮,均来自KubeSphere 团队 Thomas ...

  10. OpenFunction 应用系列之一: 以 Serverless 的方式实现 Kubernetes 日志告警

    概述 当我们将容器的日志收集到消息服务器之后,我们该如何处理这些日志?部署一个专用的日志处理工作负载可能会耗费多余的成本,而当日志体量骤增.骤降时亦难以评估日志处理工作负载的待机数量.本文提供了一种基 ...