目录
一、方法概述
- 包名:org.meteoinfo.geo.meteodata
- 作用:创建一个带有阴影效果的矢量图层。
- 返回值:VectorLayer 矢量图层
- 参数:
参数类型 | 参数名 | 描述 |
---|---|---|
GridData | gridData | 气象数据 |
LegendScheme | aLS | 图例方案 |
String | lName | 创建的矢量图层名称 |
String | fieldName | 指定了 gridData 中的哪个字段数据将被用于图层渲染 |
boolean | isSmooth | 是否应用平滑算法 |
二、源码理解
1. 取出入参的数据
//转换为多边形 POLYGON 图例方案
LegendScheme ls = aLS.convertTo(ShapeTypes.POLYGON);
//获取图例色阶数值范围
Object[] ccs = LegendManage.getContoursAndColors(ls);
double[] cValues = (double[])ccs[0];
//取出气象数据里的最大值、最小值
gridData.getMaxMinValue(maxmin);
double maxData = maxmin[0];
double minData = maxmin[1];
//取出气象数据里的经纬度数组
double[] xArray = gridData.getXArray();
double[] yArray = gridData.getYArray();
2. 生成等值线数组
int[][] S1 = new int[gridData.getYNum()][gridData.getXNum()];
/**
* gridData.getData(): 气象格点数据
* cValues:图例色阶数值范围
* xArray:经度数组
* yArray:纬度数组
* gridData.getDoubleMissingValue():缺失值
* S1:用于处理中间数据的空数组?
*/
Object[] cbs = ContourDraw.tracingContourLines(gridData.getData(), cValues, xArray, yArray, gridData.getDoubleMissingValue(), S1);
//等值线列表
List<PolyLine> ContourLines = (List)cbs[0];
//等值线图层边界
List<Border> borders = (List)cbs[1];
if (isSmooth) {
//平滑
ContourLines = Contour.smoothLines(ContourLines);
}
这里的方法tracingContourLines(),调用了wcontour包里的类方法,来生成等值线结果。(以后分析《关于等值线的绘制方法》)
public static Object[] tracingContourLines(double[][] gridData, double[] cValues, double[] X, double[] Y, double noData, int[][] S1) {
int nc = cValues.length;
List<Border> borders = Contour.tracingBorders(gridData, X, Y, S1, noData);
List<PolyLine> contourLines = Contour.tracingContourLines(gridData, X, Y, nc, cValues, noData, borders, S1);
return new Object[]{contourLines, borders};
}
3. 创建等值线 POLYGON 列表,新建矢量图层aPolygonShape
//生成等值线多边形 POLYGON 列表
List<Polygon> ContourPolygons = ContourDraw.tracingPolygons(gridData.getData(), ContourLines, borders, cValues);
//创建新图层,图元类型为 POLYGON
VectorLayer aLayer= new VectorLayer(ShapeTypes.POLYGON);
//创建新字段,用于存储每个多边形范围内的最低值
Field aDC = new Field(fieldName + "_Low", DataType.DOUBLE);
aLayer.editAddField(aDC);
//创建新字段,用于存储每个多边形范围内的最高值
aDC = new Field(fieldName + "_High", DataType.DOUBLE);
aLayer.editAddField(aDC);
4. 遍历等值线 POLYGON 列表,将其添加到矢量图层
4.1 开始遍历 POLYGON 列表
Iterator var25 = ContourPolygons.iterator();//迭代器
while(var25.hasNext()) {
......
}
4.2 获取 POLYGON 顶点列表 pList
//获取每一个Polygon对象
Polygon aPolygon = (Polygon)var25.next();
//获取aPolygon内部的最小值
double aValue = aPolygon.LowValue;
//用于存储多边形的顶点
List<PointD> pList = new ArrayList();
//遍历 aPolygon 的外轮廓点列表
Iterator var29 = aPolygon.OutLine.PointList.iterator();
//将每个点坐标复制到 PointD 对象,并添加到 pList 列表中。
PointD aPoint;
while(var29.hasNext()) {
wcontour.global.PointD pointList = (wcontour.global.PointD)var29.next();
aPoint = new PointD();
aPoint.X = pointList.X;
aPoint.Y = pointList.Y;
pList.add(aPoint);
}
//检查点列表是否为顺时针顺序
if (!GeoComputation.isClockwise(pList)) {
Collections.reverse(pList);
}
4.3 将 POLYGON 顶点列表 pList,添加到多边形对象 aPolygonShape 中
//新建多边形对象
PolygonShape aPolygonShape = new PolygonShape();
aPolygonShape.setPoints(pList); //设置顶点
aPolygonShape.setExtent(GeometryUtil.getPointsExtent(pList)); //设置范围为点列表的边界范围
aPolygonShape.lowValue = aValue;//设置最低值
//aPolygon 有洞(内部空区域)
if (aPolygon.HasHoles()) {
Iterator var36 = aPolygon.HoleLines.iterator();
//遍历洞线条列表 HoleLines,并将每个洞的点列表添加到 aPolygonShape 中
label87:
while(true) {
PolyLine holeLine;
do {
if (!var36.hasNext()) {
break label87;
}
holeLine = (PolyLine)var36.next();
} while(holeLine.PointList.size() < 3);
pList = new ArrayList();
Iterator var32 = holeLine.PointList.iterator();
while(var32.hasNext()) {
wcontour.global.PointD pointList = (wcontour.global.PointD)var32.next();
aPoint = new PointD();
aPoint.X = pointList.X;
aPoint.Y = pointList.Y;
pList.add(aPoint);
}
aPolygonShape.addHole(pList, 0);
}
}
4.4 处理一些特殊情况
如果 aPolygon 不是高值中心,且高值和低值相同,则将 aPolygonShape 的高值设置为 aValue,并根据 cValues 数组调整低值。
int valueIdx = Arrays.binarySearch(cValues, aValue);
if (valueIdx < 0) {
valueIdx = -valueIdx - 1;
}
if (valueIdx >= cValues.length - 1) {
aPolygonShape.highValue = maxData;
} else {
aPolygonShape.highValue = cValues[valueIdx + 1];
}
if (!aPolygon.IsHighCenter && aPolygon.HighValue == aPolygon.LowValue) {
aPolygonShape.highValue = aValue;
if (valueIdx == 0) {
aPolygonShape.lowValue = minData;
} else {
aPolygonShape.lowValue = cValues[valueIdx - 1];
}
}
4.5 将多边形对象 aPolygonShape 插入到 aLayer 矢量图层中
//获取图层中的图元数量 shapeNum
int shapeNum = aLayer.getShapeNum();
try {
//将 aPolygonShape 插入到 aLayer 矢量图层中的指定位置 shapeNum
if (aLayer.editInsertShape(aPolygonShape, shapeNum)) {
//如果插入成功,更新图层中与 aPolygonShape 相关的字段值。
aLayer.editCellValue(fieldName + "_Low", shapeNum, aPolygonShape.lowValue);
aLayer.editCellValue(fieldName + "_High", shapeNum, aPolygonShape.highValue);
}
} catch (Exception var34) {
Logger.getLogger(DrawMeteoData.class.getName()).log(Level.SEVERE, (String)null, var34);
}
5. 组装矢量图层的数据
//图层名
aLayer.setLayerName(lName);
//图例字段名
ls.setFieldName(fieldName + "_Low");
aLayer.setLegendScheme(ls);
//图层绘制样式:SHADED 阴影填充
aLayer.setLayerDrawType(LayerDrawType.SHADED);
return aLayer;
小白理解,如有错误,请评论指出,欢迎批评。
三、上篇文章遗留问题
问题:在方法 createShadedLayer() 绘制阴影图层中,参数lName、fieldName 的运用逻辑?在参考案例(链接)中直接传递了空字符串。
解答:
lName 用于给生成的阴影图层命名,用来标识图层。在实际应用中,这个参数可以直接传递空字符串,因为它主要用于标识图层,有时候在代码中不需要特别指定
fieldName 图例方案里的字段名,在气象数据中,可能有多个变量(如温度、湿度等),这个参数就是用来选择其中一个变量来显示。如果仅有一个变量,不需要进行显示区分(图例区分),那么也可以直接传递空字符串。
代码:
VectorLayer aLayer = new VectorLayer(ShapeTypes.POLYGON);
aLayer.setLayerName(lName);//图层名
ls.setFieldName(fieldName + "_Low");
aLayer.setLegendScheme(ls);//图例字段名
四、源代码
public static VectorLayer createShadedLayer(GridData gridData, LegendScheme aLS, String lName, String fieldName, boolean isSmooth) {
LegendScheme ls = aLS.convertTo(ShapeTypes.POLYGON);
Object[] ccs = LegendManage.getContoursAndColors(ls);
double[] cValues = (double[])ccs[0];
double[] maxmin = new double[2];
gridData.getMaxMinValue(maxmin);
double maxData = maxmin[0];
double minData = maxmin[1];
int[][] S1 = new int[gridData.getYNum()][gridData.getXNum()];
double[] xArray = gridData.getXArray();
double[] yArray = gridData.getYArray();
if (gridData.getXDelta() < 0.0D) {
ArrayUtils.reverse(xArray);
gridData.xReverse();
}
if (gridData.getYDelta() < 0.0D) {
ArrayUtils.reverse(yArray);
gridData.yReverse();
}
Object[] cbs = ContourDraw.tracingContourLines(gridData.getData(), cValues, xArray, yArray, gridData.getDoubleMissingValue(), S1);
List<PolyLine> ContourLines = (List)cbs[0];
List<Border> borders = (List)cbs[1];
if (isSmooth) {
ContourLines = Contour.smoothLines(ContourLines);
}
List<Polygon> ContourPolygons = ContourDraw.tracingPolygons(gridData.getData(), ContourLines, borders, cValues);
VectorLayer aLayer = new VectorLayer(ShapeTypes.POLYGON);
Field aDC = new Field(fieldName + "_Low", DataType.DOUBLE);
aLayer.editAddField(aDC);
aDC = new Field(fieldName + "_High", DataType.DOUBLE);
aLayer.editAddField(aDC);
Iterator var25 = ContourPolygons.iterator();
while(var25.hasNext()) {
Polygon aPolygon = (Polygon)var25.next();
double aValue = aPolygon.LowValue;
List<PointD> pList = new ArrayList();
Iterator var29 = aPolygon.OutLine.PointList.iterator();
PointD aPoint;
while(var29.hasNext()) {
wcontour.global.PointD pointList = (wcontour.global.PointD)var29.next();
aPoint = new PointD();
aPoint.X = pointList.X;
aPoint.Y = pointList.Y;
pList.add(aPoint);
}
if (!GeoComputation.isClockwise(pList)) {
Collections.reverse(pList);
}
PolygonShape aPolygonShape = new PolygonShape();
aPolygonShape.setPoints(pList);
aPolygonShape.setExtent(GeometryUtil.getPointsExtent(pList));
aPolygonShape.lowValue = aValue;
if (aPolygon.HasHoles()) {
Iterator var36 = aPolygon.HoleLines.iterator();
label87:
while(true) {
PolyLine holeLine;
do {
if (!var36.hasNext()) {
break label87;
}
holeLine = (PolyLine)var36.next();
} while(holeLine.PointList.size() < 3);
pList = new ArrayList();
Iterator var32 = holeLine.PointList.iterator();
while(var32.hasNext()) {
wcontour.global.PointD pointList = (wcontour.global.PointD)var32.next();
aPoint = new PointD();
aPoint.X = pointList.X;
aPoint.Y = pointList.Y;
pList.add(aPoint);
}
aPolygonShape.addHole(pList, 0);
}
}
int valueIdx = Arrays.binarySearch(cValues, aValue);
if (valueIdx < 0) {
valueIdx = -valueIdx - 1;
}
if (valueIdx >= cValues.length - 1) {
aPolygonShape.highValue = maxData;
} else {
aPolygonShape.highValue = cValues[valueIdx + 1];
}
if (!aPolygon.IsHighCenter && aPolygon.HighValue == aPolygon.LowValue) {
aPolygonShape.highValue = aValue;
if (valueIdx == 0) {
aPolygonShape.lowValue = minData;
} else {
aPolygonShape.lowValue = cValues[valueIdx - 1];
}
}
int shapeNum = aLayer.getShapeNum();
try {
if (aLayer.editInsertShape(aPolygonShape, shapeNum)) {
aLayer.editCellValue(fieldName + "_Low", shapeNum, aPolygonShape.lowValue);
aLayer.editCellValue(fieldName + "_High", shapeNum, aPolygonShape.highValue);
}
} catch (Exception var34) {
Logger.getLogger(DrawMeteoData.class.getName()).log(Level.SEVERE, (String)null, var34);
}
}
aLayer.setLayerName(lName);
ls.setFieldName(fieldName + "_Low");
aLayer.setLegendScheme(ls);
aLayer.setLayerDrawType(LayerDrawType.SHADED);
return aLayer;
}