JAVA:wContour+netcdfAll实现格点数据生成等值线的geojson

  • 引入依赖
 1         <dependency>
 2             <groupId>edu.ucar</groupId>
 3             <artifactId>netcdfAll</artifactId>
 4             <version>5.5.4</version>
 5             <scope>system</scope>
 6             <systemPath>${pom.basedir}/../lib/netcdfAll-5.5.4-SNAPSHOT-x.jar</systemPath>
 7         </dependency>
 8                     <dependency>
 9                 <groupId>org.meteothink</groupId>
10                 <artifactId>wContour</artifactId>
11                 <version>1.7.1</version>
12             </dependency>
  • java代码
  1   2 
  3 import org.json.JSONObject;
  4 import ucar.nc2.NetcdfFile;
  5 import ucar.nc2.Variable;
  6 import ucar.nc2.dataset.NetcdfDataset;
  7 import wcontour.Contour;
  8 import wcontour.global.Border;
  9 import wcontour.global.PointD;
 10 import wcontour.global.PolyLine;
 11 import wcontour.global.Polygon;
 12 
 13 import java.io.BufferedWriter;
 14 import java.io.FileWriter;
 15 import java.io.IOException;
 16 import java.math.BigDecimal;
 17 import java.text.DecimalFormat;
 18 import java.util.*;
 19 
 20 public class IsosurfacesUtil {
 21 
 22     private static String rootPath = "E:\\Desktop\\";
 23 
 24     private static final double _undefData = -9999.0;
 25     private static final double invalidValueDou = -9999.0;
 26     private static final double scaleFactorDou = 1.0;
 27 
 28     public static void main(String[] args) throws IOException {
 29         Map<String, Object> stringObjectMap = isolineProcess();
 30         String strGeojson = (String) stringObjectMap.get("geojson");
 31         String strFile = rootPath + "012.geojson";
 32         BufferedWriter writer = new BufferedWriter(new FileWriter(strFile));
 33         writer.write(strGeojson);
 34         writer.close();
 35     }
 36 
 37 
 38 
 39 
 40     public static Map<String, Object> isolineProcess() throws IOException {
 41         Map<String, Object> resMap = new HashMap<String, Object>();
 42         String filePath = "E:\\Desktop\\012.grib";
 43         String element = "Temperature_surface";
 44         int depthIndex = 2;
 45         int timeIndex = 1;
 46         //获取NC的数据
 47         Map map = getNcData(filePath,element,depthIndex,timeIndex);
 48         if(map == null || map.size()==0){
 49             return resMap;
 50         }
 51         double[] dataInterval = new double[]{-14,-13,-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14};
 52         String strGeojson = nc2EquiSurface(map, dataInterval);
 53         resMap.put("geojson", strGeojson);
 54         resMap.put("dataArr", map.get("eleData"));
 55         return resMap;
 56     }
 57 
 58 
 59     public static <T> Map getNcData(String ncpath,String element,int depthIndex,int timeIndex) throws IOException {
 60         String lonVarName = "lon";
 61         String latVarName = "lat";
 62         //加载nc文件
 63         NetcdfFile ncfile =  NetcdfDataset.open(ncpath);
 64         //读取经纬度数据
 65         Variable varLon = ncfile.findVariable(lonVarName);
 66         Variable varLat = ncfile.findVariable(latVarName);
 67         Object lonObj = null;
 68         Object latObj = null;
 69         lonObj = (Object) varLon.read().copyToNDJavaArray();
 70         latObj = (Object) varLat.read().copyToNDJavaArray();
 71         Map map = new HashMap();
 72         map = readNCLonLat(map,lonObj,latObj);
 73         int latLength = (int) map.get("latlength");
 74         int lonLength = (int) map.get("lonlength");
 75 
 76         //读取变量数据
 77         Variable varPre = ncfile.findVariable(element);
 78 
 79         Object pre = null;
 80         pre = (Object) varPre.read().copyToNDJavaArray();
 81         String className = pre.getClass().getComponentType().getName();
 82 
 83         if("[[f".equalsIgnoreCase(className)){
 84             float[][][] dataArr = (float[][][])pre;
 85             double[][] dPre = new double[dataArr[0].length][dataArr[0][0].length];
 86             DecimalFormat df = new DecimalFormat("#.00");
 87             for (int i = 0, len = dataArr[0].length; i < len; i++) {
 88                 float[] _pre = dataArr[0][i];
 89                 for (int j =  _pre.length - 1, jlen = 0; j >= jlen; j--) {
 90                     double value = Double.parseDouble(String.valueOf(_pre[j]))- 273.15;
 91                     if(Double.compare(value, invalidValueDou) == 0){
 92                         dPre[i][j] = invalidValueDou;
 93                         continue;//无效值跳过
 94                     }
 95                     dPre[i][j] = Double.parseDouble(df.format(value * scaleFactorDou));
 96 
 97                 }
 98             }
 99             map.put("eleData", dPre);
100         }
101         return map;
102     }
103 
104 
105     private static Map readNCLonLat(Map map, Object lonObj, Object latObj) {
106 
107         String lonclassName = lonObj.getClass().getComponentType().getName();
108         int lonLength = 1;
109         int latLength = 1;
110         if ("[s".equalsIgnoreCase(lonclassName)) {
111             short[] lonArr = (short[]) lonObj;
112             short[] latArr = (short[]) latObj;
113             lonLength = lonArr.length;
114             latLength = latArr.length;
115             //创建double数组存放经纬度数据,方便后续计算
116             double[] dLon = new double[lonArr.length], dLat = new double[latArr.length];
117             for (int i = 0, len = lonArr.length; i < len; i++) {
118                 dLon[i] = Double.parseDouble(String.valueOf(lonArr[i]));
119             }
120             for (int i = 0, len = latArr.length - 1 ; i >= len; i--) {
121                 dLat[i] = Double.parseDouble(String.valueOf(latArr[latArr.length-i-1]));
122             }
123             map.put("lon", dLon);
124             map.put("lat", dLat);
125         }
126         if ("float".equalsIgnoreCase(lonclassName)) {
127             float[] lonArr = (float[]) lonObj;
128             float[] latArr = (float[]) latObj;
129             lonLength = lonArr.length;
130             latLength = latArr.length;
131             //创建double数组存放经纬度数据,方便后续计算
132             double[] dLon = new double[lonArr.length], dLat = new double[latArr.length];
133             for (int i = 0, len = lonArr.length; i < len; i++) {
134                 dLon[i] = Double.parseDouble(String.valueOf(lonArr[i]));
135             }
136             for (int i = 0, len = latArr.length; i < len; i++) {
137                 dLat[i] = Double.parseDouble(String.valueOf(latArr[latArr.length-i-1]));
138             }
139             map.put("lon", dLon);
140             map.put("lat", dLat);
141         }
142         map.put("lonlength", lonLength);
143         map.put("latlength", latLength);
144         return map;
145     }
146 
147 
148     public static String nc2EquiSurface(Map ncData, double[] dataInterval) {
149         String geojsonpogylon = "";
150         String geojsonpogylona = "";
151 
152         List<PolyLine> cPolylineList;
153         List<Polygon> cPolygonList;
154 
155         double[][] _gridData = (double[][]) ncData.get("eleData");
156         int[][] S1 = new int[_gridData.length][_gridData[0].length];
157         double[] _X = (double[]) ncData.get("lon"), _Y = (double[]) ncData.get("lat");
158         System.out.println("dataInterval: " + Arrays.toString(dataInterval));
159         System.out.println("Min temperature: " + Arrays.stream(_gridData).flatMapToDouble(Arrays::stream).min().getAsDouble());
160         System.out.println("Max temperature: " + Arrays.stream(_gridData).flatMapToDouble(Arrays::stream).max().getAsDouble());
161         System.out.println("_gridData dimensions: " + _gridData.length + " x " + _gridData[0].length);
162         System.out.println("_X length: " + _X.length);
163         System.out.println("_Y length: " + _Y.length);
164 
165         List<Border> _borders = Contour.tracingBorders(_gridData, _X, _Y, S1, _undefData);
166         int nc = dataInterval.length;
167         cPolylineList = Contour.tracingContourLines(_gridData, _X, _Y, nc, dataInterval, _undefData, _borders, S1);// 生成等值线
168 
169         cPolylineList = Contour.smoothLines(cPolylineList);// 平滑
170         cPolygonList = Contour.tracingPolygons(_gridData, cPolylineList,_borders, dataInterval);
171 
172         geojsonpogylon = getPolygonGeoJson(cPolygonList);
173 
174 //        geojsonpogylona = getPolylineGeoJson(cPolylineList);
175         return geojsonpogylon;
176     }
177 
178 
179 
180     public static String getPolygonGeoJson(List<Polygon> cPolygonList) {
181         String geo = null;
182         String geometry = " { \"type\":\"Feature\",\"geometry\":";
183         String properties = ",\"properties\":{ \"value\":";
184 
185         String head = "{\"type\": \"FeatureCollection\"," + "\"features\": [";
186         String end = "  ] }";
187         if (cPolygonList == null || cPolygonList.size() == 0) {
188             return null;
189         }
190         try {
191             for (Polygon pPolygon : cPolygonList) {
192                 List<Object> ptsTotal = new ArrayList<Object>();
193                 for (PointD ptd : pPolygon.OutLine.PointList) {
194                     List<Double> pt = new ArrayList<Double>();
195                     pt.add(doubleFormat(ptd.X));
196                     pt.add(doubleFormat(ptd.Y));
197                     ptsTotal.add(pt);
198                 }
199                 List<Object> list3D = new ArrayList<Object>();
200                 list3D.add(ptsTotal);
201                 JSONObject js = new JSONObject();
202                 js.put("type", "Polygon");
203                 js.put("coordinates", list3D);
204 
205                 geo = geometry + js + properties  +pPolygon.LowValue + "} }" + "," + geo;
206             }
207             if (geo.contains(",")) {
208                 geo = geo.substring(0, geo.lastIndexOf(","));
209             }
210 
211             geo = head + geo + end;
212         } catch (Exception e) {
213             e.printStackTrace();
214             return geo;
215         }
216         return geo;
217     }
218 
219     public static String getPolylineGeoJson(List<PolyLine> cPolylineList) {
220         if (cPolylineList == null || cPolylineList.size() == 0) {
221             return null;
222         }
223 
224         String collectionFormat = "{\"type\": \"FeatureCollection\"," + "\"features\": [ %s ] }";
225         String geometryFormat = "{\"type\":\"Feature\",\"geometry\": %s ,\"properties\":{ \"value\": %s }}";
226 
227         List<String> geoList = new ArrayList<>();
228         for (int i = 0; i < cPolylineList.size(); i++) {
229             PolyLine pPolyline = cPolylineList.get(i);
230             List<Object> ptsTotal = new ArrayList<Object>();
231             for (PointD ptd : pPolyline.PointList) {
232                 List<Double> pt = new ArrayList<Double>();
233                 pt.add(doubleFormat(ptd.X));
234                 pt.add(doubleFormat(ptd.Y));
235                 ptsTotal.add(pt);
236             }
237             cn.hutool.json.JSONObject js = new cn.hutool.json.JSONObject();
238             js.set("type", "LineString");
239             js.set("coordinates", ptsTotal);
240             js.set("id", pPolyline.Value + "_" + i);
241 
242             String geo = String.format(geometryFormat, js, pPolyline.Value);
243             geoList.add(geo);
244         }
245         return String.format(collectionFormat, String.join(", ", geoList));
246     }
247 
248     /**
249      * double保留两位小数
250      */
251     public static double doubleFormat(double d) {
252         BigDecimal bg = new BigDecimal(d);
253         double f1 = bg.setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue();
254         return f1;
255     }
256 }
  • 注意事项
  1. 各类型数据需要填充不同的数据处理
  2. 经纬度需要按照从大到小的顺序
posted @ 2025-01-16 16:05  薛定谔的笨猫  阅读(178)  评论(1)    收藏  举报