对绘制气象色斑图createShadedLayer()方法的简单理解(meteoinfo包)

一、方法概述

  • 包名:org.meteoinfo.geo.meteodata
  • 作用:创建一个带有阴影效果的矢量图层。
  • 返回值:VectorLayer 矢量图层
  • 参数:
参数类型参数名描述
GridDatagridData气象数据
LegendSchemeaLS图例方案
StringlName创建的矢量图层名称
StringfieldName指定了 gridData 中的哪个字段数据将被用于图层渲染
booleanisSmooth是否应用平滑算法

二、源码理解

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;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值