From 45a773850057dd90c4292d30715b4f9dfdc86740 Mon Sep 17 00:00:00 2001 From: 13693261870 <252740454@qq.com> Date: 星期一, 04 十二月 2023 13:42:20 +0800 Subject: [PATCH] 屏蔽NoData --- src/main/java/com/moon/server/service/data/RasterAnalysisService.java | 481 +++++++++++++++++++++++++++++++++++++++-------------- 1 files changed, 352 insertions(+), 129 deletions(-) diff --git a/src/main/java/com/moon/server/service/data/RasterAnalysisService.java b/src/main/java/com/moon/server/service/data/RasterAnalysisService.java index 777a207..14d2d17 100644 --- a/src/main/java/com/moon/server/service/data/RasterAnalysisService.java +++ b/src/main/java/com/moon/server/service/data/RasterAnalysisService.java @@ -1,10 +1,15 @@ package com.moon.server.service.data; +import com.alibaba.fastjson.JSONObject; import com.moon.server.entity.all.StaticData; import com.moon.server.entity.data.AnalysisResultEntity; import com.moon.server.entity.data.MetaEntity; import com.moon.server.entity.data.PublishEntity; +import com.moon.server.helper.GeoHelper; import com.moon.server.helper.PathHelper; +import com.moon.server.helper.StringHelper; +import com.moon.server.helper.WebHelper; +import com.moon.server.service.all.WebSocketService; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.gdal.gdal.Band; @@ -13,10 +18,14 @@ import org.gdal.gdal.gdal; import org.gdal.ogr.Geometry; import org.gdal.ogr.ogr; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import javax.annotation.Resource; +import java.awt.geom.Point2D; import java.io.File; +import java.io.FileWriter; +import java.io.IOException; import java.util.*; /** @@ -26,6 +35,9 @@ */ @Service public class RasterAnalysisService { + @Value("${sys.gdal_path}") + String gdalPath; + @Resource PathHelper pathHelper; @@ -33,6 +45,102 @@ PublishService publishService; private final static Log log = LogFactory.getLog(RasterAnalysisService.class); + + /** + * 娴嬭瘯 + * <p> + * POINT (26.72 -48.58) + * LINESTRING(18.44 -46.69,20.14 -45.93) + * POLYGON ((5.11 -41.64,7.68 -43.59,4.73 -43.3,5.11 -41.64)) + * POLYGON ((42.6 -40.3,49.1 -40.4,49.1 -65.7,46.3 -65.6,42.6 -40.3)) + */ + public List<AnalysisResultEntity> test(Geometry geo, Integer size) { + List<AnalysisResultEntity> rs = new ArrayList<>(); + AnalysisResultEntity entity = new AnalysisResultEntity(); + entity.setLayerName("Test"); + + openRaster(entity, "D:\\Moon\\data\\DOM\\Lunar_LRO_LOLA_ClrShade_Global_128ppd_v04_2.tif", geo, size); + rs.add(entity); + + return rs; + } + + /** + * 浣跨敤WKT鏌ヨ鍒嗘瀽锛岀粨鏋滀互娑堟伅鎺ㄩ�� + */ + public void analysisForPost(Geometry geo, Integer size, String token) { + List<PublishEntity> pubs = publishService.selectRaster(); + if (null == pubs || pubs.isEmpty()) { + return; + } + + //for (PublishEntity pub : pubs) { + pubs.parallelStream().forEach(pub -> { + try { + AnalysisResultEntity entity = new AnalysisResultEntity(token); + entity.setLayerName(pub.getName()); + entity.setUnit(pub.getUnit()); + + List<MetaEntity> metas = publishService.selectMetasByPubid(pub.getId()); + if (null == metas || metas.isEmpty()) { + setError(entity, "鎵句笉鍒板彂甯冩暟鎹�"); + postInfo(entity); + return; + } + + String filePath = getFilePath(metas); + File file = new File(filePath); + if (!file.exists() || file.isDirectory()) { + setError(entity, "婧愭暟鎹笉瀛樺湪"); + postInfo(entity); + return; + } + + openRaster(entity, filePath, geo, size); + postInfo(entity); + } catch (Exception ex) { + log.error(ex.getMessage(), ex); + } + }); + } + + /** + * 鑾峰彇鏂囦欢璺緞 + */ + private String getFilePath(List<MetaEntity> metas) throws IOException { + String basePath = pathHelper.getConfig().getUploadPath() + File.separator; + if (metas.size() == 1) { + return basePath + metas.get(0).getPath(); + } + + String tempPath = pathHelper.getTempPath() + File.separator, guid = StringHelper.getGuid(); + String fileList = tempPath + guid + ".txt"; + FileWriter fw = new FileWriter(fileList); + for (int i = 0, c = metas.size(); i < c; i++) { + String str = (i > 0 ? "\r\n" : "") + basePath + metas.get(i).getPath(); + fw.write(str.toCharArray()); + } + fw.close(); + + String vrt = tempPath + guid + ".vrt"; + String cmd = String.format("\"%s\\gdalbuildvrt.exe\" -input_file_list \"%s\" \"%s\"", gdalPath, fileList, vrt); + WebHelper.exec(cmd); + + return vrt; + } + + /** + * 鎺ㄩ�佹秷鎭� + */ + private void postInfo(AnalysisResultEntity entity) throws IOException { + JSONObject map = new JSONObject(); + map.put("analysisForPost", entity); + + String json = JSONObject.toJSONString(map); + //System.out.println(json) + + WebSocketService.broadCastInfo(json); + } /** * 鍒嗘瀽鏂规硶 @@ -46,26 +154,30 @@ } for (PublishEntity pub : pubs) { - AnalysisResultEntity entity = new AnalysisResultEntity(); - entity.setLayerName(pub.getName()); + try { + AnalysisResultEntity entity = new AnalysisResultEntity(); + entity.setLayerName(pub.getName()); + entity.setUnit(pub.getUnit()); - List<MetaEntity> metas = publishService.selectMetasByPubid(pub.getId()); - if (null == metas || metas.isEmpty()) { - setError(entity, "鎵句笉鍒板彂甯冩暟鎹�"); - continue; + List<MetaEntity> metas = publishService.selectMetasByPubid(pub.getId()); + if (null == metas || metas.isEmpty()) { + setError(entity, "鎵句笉鍒板彂甯冩暟鎹�"); + continue; + } + + String filePath = getFilePath(metas); + File file = new File(filePath); + if (!file.exists() || file.isDirectory()) { + setError(entity, "婧愭暟鎹笉瀛樺湪"); + continue; + } + + openRaster(entity, filePath, geo, size); + rs.add(entity); + } catch (Exception ex) { + log.error(ex.getMessage(), ex); } - - String filePath = pathHelper.getConfig().getUploadPath() + File.separator + metas.get(0).getPath(); - File file = new File(filePath); - if (!file.exists() || file.isDirectory()) { - setError(entity, "婧愭暟鎹笉瀛樺湪"); - continue; - } - - openRaster(entity, filePath, geo, size); - rs.add(entity); } - return rs; } @@ -75,6 +187,7 @@ private void openRaster(AnalysisResultEntity entity, String filePath, Geometry geo, int size) { Dataset ds = null; try { + // filePath = "D:\\Moon\\data\\DOM\\test.tif" ds = gdal.Open(filePath); if (null == ds) { throw new Exception("鎵撳紑鏍呮牸鏁版嵁澶辫触"); @@ -85,7 +198,7 @@ analysisPoint(entity, ds, geo, size); break; case ogr.wkbLineString: - analysisPolyline(entity, ds, geo); + analysisPolyline(entity, ds, geo, size); break; default: analysisPolygon(entity, ds, geo); @@ -104,93 +217,126 @@ /** * 鍒嗘瀽鐐� */ - public void analysisPoint(AnalysisResultEntity entity, Dataset ds, Geometry point, int size) { - double x = point.GetX(), y = point.GetY(); + public void analysisPoint(AnalysisResultEntity entity, Dataset ds, Geometry geo, int size) { double[] transform = ds.GetGeoTransform(); - // double rotationX = transform[2]; double rotationY = transform[4] - double minX = transform[0], pixelWidth = transform[1], maxY = transform[3], pixelHeight = transform[5]; + double pixelWidth = transform[1], pixelHeight = Math.abs(transform[5]); - int bandCount = ds.getRasterCount(); - int xPixel = (int) Math.floor((x - minX) / pixelWidth); - int yPixel = (int) Math.floor((maxY - y) / Math.abs(pixelHeight)); + double buffer = Math.max(pixelWidth, pixelHeight) * size; + geo = geo.Buffer(buffer); - List<double[]> list = new ArrayList<>(); - for (int i = 1; i <= bandCount; i++) { - double[] pixelValues = new double[size * size]; - Band band = ds.GetRasterBand(i); - band.ReadRaster(xPixel, yPixel, size, size, pixelValues); - - list.add(pixelValues); - } - - processResult(entity, list); + analysisPolygon(entity, ds, geo); } /** * 鍒嗘瀽绾� */ - public void analysisPolyline(AnalysisResultEntity entity, Dataset ds, Geometry polyline) { + public void analysisPolyline(AnalysisResultEntity entity, Dataset ds, Geometry geo, int size) { double[] transform = ds.GetGeoTransform(); - // double rotationX = transform[2]; double rotationY = transform[4] + int xSize = ds.getRasterXSize(), ySize = ds.getRasterYSize(); double minX = transform[0], pixelWidth = transform[1], maxY = transform[3], pixelHeight = transform[5]; - double[] bounds = new double[6]; - polyline.GetEnvelope(bounds); - double startX = bounds[0], endX = bounds[1], startY = bounds[2], endY = bounds[3]; - + double len = 0; int bandCount = ds.getRasterCount(); - int xStartPixel = (int) Math.floor((startX - minX) / pixelWidth); - int yStartPixel = (int) Math.floor((maxY - startY) / Math.abs(pixelHeight)); - int xEndPixel = (int) Math.floor((endX - minX) / pixelWidth); - int yEndPixel = (int) Math.floor((maxY - endY) / Math.abs(pixelHeight)); + double lineDis = getPolylineDistance(geo); + double distance = lineDis / Math.max(geo.GetPointCount(), size); - List<Double> list = new ArrayList<>(); - for (int y = Math.min(yStartPixel, yEndPixel); y <= Math.max(yStartPixel, yEndPixel); y++) { - for (int x = Math.min(xStartPixel, xEndPixel); x <= Math.max(xStartPixel, xEndPixel); x++) { - Geometry point = new Geometry(ogr.wkbPoint); - point.AddPoint(minX + pixelWidth * x, maxY - pixelHeight * y); - if (polyline.Contains(point)) { - for (int i = 1; i <= bandCount; i++) { - double[] values = new double[1]; - ds.GetRasterBand(i).ReadRaster(x, y, 1, 1, values); - list.add(values[0]); - } + List<double[]> points = getPointsByDistance(geo, distance); + for (int i = 0, c = points.size(); i < c; i++) { + double[] xy = points.get(i); + if (i > 0) { + double[] p = points.get(i - 1); + len += GeoHelper.getDistance(p[0], p[1], xy[0], xy[1]); + } + + int xPixel = (int) Math.floor((xy[0] - minX) / pixelWidth); + int yPixel = (int) Math.floor((maxY - xy[1]) / Math.abs(pixelHeight)); + if (xPixel < 1 || xPixel > xSize || yPixel < 1 || yPixel > ySize) { + continue; + } + + List<Double> vals = new ArrayList<>(); + for (int j = 1; j <= bandCount; j++) { + double[] pixelValues = new double[1]; + ds.GetRasterBand(j).ReadRaster(xPixel, yPixel, 1, 1, pixelValues); + if (!Double.isNaN(pixelValues[0])) { + vals.add(WebHelper.round(pixelValues[0], 3)); } } + if (vals.size() > 0) { + entity.addPoint(xy[0], xy[1], len, vals); + } } - - processResult(list, entity); } /** * 鍒嗘瀽闈� */ - public void analysisPolygon(AnalysisResultEntity entity, Dataset ds, Geometry polygon) { + public void analysisPolygon(AnalysisResultEntity entity, Dataset ds, Geometry geo) { double[] transform = ds.GetGeoTransform(); - // double rotationX = transform[2]; double rotationY = transform[4] - double minX = transform[0], pixelWidth = transform[1], maxY = transform[3], pixelHeight = transform[5]; - double[] env = new double[6]; - polygon.GetEnvelope(env); + int xSize = ds.getRasterXSize(), ySize = ds.getRasterYSize(); + double minX = transform[0], pixelWidth = transform[1], maxY = transform[3], pixelHeight = Math.abs(transform[5]), rotationX = transform[2], rotationY = transform[4]; + double[] env = new double[4]; + geo.GetEnvelope(env); + entity.addPoint(geo.Centroid().GetX(), geo.Centroid().GetY(), 0, null); - int xMinPixel = (int) Math.floor((env[0] - minX) / pixelWidth); - int yMinPixel = (int) Math.floor((maxY - env[3]) / Math.abs(pixelHeight)); - int xMaxPixel = (int) Math.floor((env[1] - minX) / pixelWidth); - int yMaxPixel = (int) Math.floor((maxY - env[2]) / Math.abs(pixelHeight)); - - int bandCount = ds.getRasterCount(); - int geoWidth = Math.abs(xMaxPixel - xMinPixel); - int geoHeight = Math.abs(yMaxPixel - yMinPixel); - - List<double[]> list = new ArrayList<>(); - for (int i = 1; i <= bandCount; i++) { - Band band = ds.GetRasterBand(i); - double[] pixelValues = new double[geoWidth * geoHeight]; - band.ReadRaster(xMinPixel, yMinPixel, geoWidth, geoHeight, pixelValues); - - list.add(pixelValues); + int xMinPixel = Math.max((int) Math.floor((env[0] - minX) / pixelWidth), 1); + int yMinPixel = Math.max((int) Math.floor((maxY - env[3]) / pixelHeight), 1); + int xMaxPixel = Math.min((int) Math.floor((env[1] - minX) / pixelWidth), xSize); + int yMaxPixel = Math.min((int) Math.floor((maxY - env[2]) / pixelHeight), ySize); + if (xMaxPixel < 1 || yMaxPixel < 1 || xMaxPixel - xMinPixel < 0 || yMaxPixel - yMinPixel < 0) { + setError(entity, "鏌ヨ鑼冨洿鏃犳晥"); + return; } - processResult(entity, list); + int bandCount = ds.getRasterCount(); + int width = xMaxPixel - xMinPixel; + int height = yMaxPixel - yMinPixel; + if (width * height > StaticData.I64 * StaticData.I64) { + readRasterForBlocks(entity, ds, bandCount, xMinPixel, yMinPixel, width, height); + return; + } + + for (int i = 1; i <= bandCount; i++) { + double[] pixelValues = new double[width * height]; + ds.GetRasterBand(i).ReadRaster(xMinPixel, yMinPixel, width, height, pixelValues); + setBandVals(entity, pixelValues); + } + } + + /** + * 鎸夌収鍧楄鍙栨爡鏍兼暟鎹� + */ + private void readRasterForBlocks(AnalysisResultEntity entity, Dataset ds, int bandCount, int xMinPixel, int yMinPixel, int width, int height) { + List<Integer> xList = getSamples(xMinPixel, width - 1); + List<Integer> yList = getSamples(yMinPixel, height - 1); + + double[] pixelValues = new double[1]; + for (int i = 1; i <= bandCount; i++) { + List<Double> list = new ArrayList<>(); + for (Integer x : xList) { + for (Integer y : yList) { + ds.GetRasterBand(i).ReadRaster(x, y, 1, 1, pixelValues); + if (!Double.isNaN(pixelValues[0])) { + list.add(pixelValues[0]); + } + } + } + setBandVals(entity, list); + } + } + + /** + * 鑾峰彇鎶芥牱鍒楄〃 + */ + private List<Integer> getSamples(int start, int strip) { + List<Integer> list = new ArrayList<>(); + + double avg = 1.0 * strip / (StaticData.I64 - 1); + for (int i = 0; i < StaticData.I64; i++) { + list.add(start + (int) Math.ceil(avg * i)); + } + + return list; } /** @@ -202,37 +348,143 @@ } /** - * 澶勭悊缁撴灉 + * 璁剧疆Band鍊� */ - private void processResult(AnalysisResultEntity entity, List<double[]> list) { + private void setBandVals(AnalysisResultEntity entity, double[] pixelValues) { + if (null == pixelValues || pixelValues.length == 0) { + return; + } + + List<Double> list = new ArrayList<>(); + for (double val : pixelValues) { + if (!Double.isNaN(val) && val > Integer.MIN_VALUE) { + list.add(val); + } + } + setBandVals(entity, list); + } + + /** + * 璁剧疆Band鍊� + */ + private void setBandVals(AnalysisResultEntity entity, List<Double> list) { if (null == list || list.isEmpty()) { return; } - List<Double> rs = new ArrayList<>(); - for (double[] ds : list) { - if (null != ds && ds.length > 0) { - for (double d : ds) { - rs.add(d); - } - } - } - - processResult(rs, entity); + double min = Collections.min(list); + double max = Collections.max(list); + double avg = list.stream().mapToDouble(Double::valueOf).average().getAsDouble(); + entity.addBandVals(min, avg, max); } /** - * 澶勭悊缁撴灉 + * 鑾峰彇鎶樼嚎璺濈 */ - private void processResult(List<Double> rs, AnalysisResultEntity entity) { - double avg = rs.stream().mapToDouble(Double::valueOf).average().getAsDouble(); + private double getPolylineDistance(Geometry geo) { + double dis = 0; + for (int i = 0, c = geo.GetPointCount() - 1; i < c; i++) { + double[] xy1 = geo.GetPoint(i); + double[] xy2 = geo.GetPoint(i + 1); - entity.setMin(Collections.min(rs)); - entity.setMax(Collections.max(rs)); - entity.setAvg(avg); + dis += GeoHelper.getDistance(xy1[0], xy1[1], xy2[0], xy2[1]); + } + + return dis; } - public void processClippedDataByLine(String imagePath, String geometryString) { + /** + * 鏍规嵁璺濈鑾峰彇鑺傜偣 + */ + private List<double[]> getPointsByDistance(Geometry geo, double distance) { + List<double[]> list = new ArrayList<>(); + + int c = geo.GetPointCount() - 1; + for (int i = 0; i < c; i++) { + double[] xy1 = geo.GetPoint(i); + double[] xy2 = geo.GetPoint(i + 1); + list.add(xy1); + + double lineDis = GeoHelper.getDistance(xy1[0], xy1[1], xy2[0], xy2[1]); + if (lineDis < distance) { + continue; + } + + double d = distance; + double angle = GeoHelper.getAngle(xy1[0], xy1[1], xy2[0], xy2[1]); + while (d + distance * StaticData.D05 < lineDis) { + Point2D point = GeoHelper.getPointByDistanceAndAngle(xy1[0], xy1[1], angle, d); + list.add(new double[]{point.getX(), point.getY()}); + d += distance; + } + } + list.add(geo.GetPoint(c)); + + return list; + } + + /** + * 鍒嗘瀽鐐� 2 + */ + public void analysisPoint2(AnalysisResultEntity entity, Dataset ds, Geometry geo, int size) { + double x = geo.GetX(), y = geo.GetY(); + double[] transform = ds.GetGeoTransform(); + // double rotationX = transform[2]; double rotationY = transform[4] + double minX = transform[0], pixelWidth = transform[1], maxY = transform[3], pixelHeight = transform[5]; + + int bandCount = ds.getRasterCount(); + int xPixel = (int) Math.floor((x - minX) / pixelWidth); + int yPixel = (int) Math.floor((maxY - y) / Math.abs(pixelHeight)); + + for (int i = 1; i <= bandCount; i++) { + double[] pixelValues = new double[size * size]; + Band band = ds.GetRasterBand(i); + band.ReadRaster(xPixel, yPixel, size, size, pixelValues); + } + } + + /** + * 鍒嗘瀽绾� 2 + */ + public void analysisPolyline2(AnalysisResultEntity entity, Dataset ds, Geometry geo, int size) { + double[] transform = ds.GetGeoTransform(); + // double rotationX = transform[2]; double rotationY = transform[4] + double minX = transform[0], pixelWidth = transform[1], maxY = transform[3], pixelHeight = Math.abs(transform[5]); + + double buffer = Math.max(pixelWidth, pixelHeight) * size; + double[] env = new double[4]; + geo = geo.Buffer(buffer); + geo.GetEnvelope(env); + + int xMinPixel = (int) Math.floor((env[0] - minX) / pixelWidth); + int yMinPixel = (int) Math.floor((maxY - env[3]) / pixelHeight); + int xMaxPixel = (int) Math.floor((env[1] - minX) / pixelWidth); + int yMaxPixel = (int) Math.floor((maxY - env[2]) / pixelHeight); + + int bandCount = ds.getRasterCount(); + int xMin = Math.min(xMinPixel, xMaxPixel); + int xMax = Math.max(xMinPixel, xMaxPixel); + int yMin = Math.min(yMinPixel, yMaxPixel); + int yMax = Math.max(yMinPixel, yMaxPixel); + + List<Double> list = new ArrayList<>(); + for (int y = yMin; y <= yMax; y++) { + for (int x = xMin; x <= xMax; x++) { + Geometry point = new Geometry(ogr.wkbPoint); + point.AddPoint(minX + pixelWidth * x, maxY - pixelHeight * y); + if (geo.Intersects(point)) { + for (int i = 1; i <= bandCount; i++) { + double[] values = new double[1]; + ds.GetRasterBand(i).ReadRaster(x, y, 1, 1, values); + list.add(values[0]); + } + } + } + } + // processResult(list, entity) + } + + private void processClippedDataByLine(String imagePath, String geometryString) { // 娉ㄥ唽GDAL椹卞姩 gdal.AllRegister(); // 鎵撳紑鏍呮牸鍥惧儚鏁版嵁闆� @@ -260,7 +512,7 @@ } } - public static Dataset clipRaster(Dataset dataset, Geometry geometry) { + private Dataset clipRaster(Dataset dataset, Geometry geometry) { Vector<String> warpOptions = new Vector<>(); warpOptions.add("-crop_to_cutline"); warpOptions.add("-cutline"); @@ -268,34 +520,5 @@ warpOptions.add("-dstalpha"); return gdal.Warp("", new Dataset[]{dataset}, new WarpOptions(warpOptions)); - } - - public void processClippedDataByPolygon(String imagePath, String geometryString) { - // 娉ㄥ唽GDAL椹卞姩 - gdal.AllRegister(); - // 鎵撳紑鏍呮牸鍥惧儚鏁版嵁闆� - Dataset dataset = gdal.Open(imagePath); - if (dataset == null) { - throw new RuntimeException("Failed to open raster dataset."); - } - - Geometry geometry = Geometry.CreateFromWkt(geometryString); - - Dataset clippedDataset = clipRaster(dataset, geometry); - - int width = clippedDataset.GetRasterXSize(); - int height = clippedDataset.GetRasterYSize(); - int bandCount = clippedDataset.getRasterCount(); - - double[] bandSum = new double[bandCount]; - for (int bandIndex = 1; bandIndex <= bandCount; bandIndex++) { - Band band = clippedDataset.GetRasterBand(bandIndex); - - double[] pixelValues = new double[width * height]; - band.ReadRaster(0, 0, width, height, pixelValues); - - // 澶氭尝娈靛綊涓�鍖栧鐞� - bandSum[bandIndex - 1] = pixelValues[0]; - } } } -- Gitblit v1.9.3