[update] 修改光伏板和名称匹配逻辑
This commit is contained in:
@ -17,7 +17,10 @@ import org.dromara.common.satoken.utils.LoginHelper;
|
|||||||
import org.dromara.facility.constant.FacRedisKeyConstant;
|
import org.dromara.facility.constant.FacRedisKeyConstant;
|
||||||
import org.dromara.facility.domain.FacMatrix;
|
import org.dromara.facility.domain.FacMatrix;
|
||||||
import org.dromara.facility.domain.FacPhotovoltaicPanel;
|
import org.dromara.facility.domain.FacPhotovoltaicPanel;
|
||||||
import org.dromara.facility.domain.dto.geojson.*;
|
import org.dromara.facility.domain.dto.geojson.FacFeatureByPlane;
|
||||||
|
import org.dromara.facility.domain.dto.geojson.FacFeatureByPoint;
|
||||||
|
import org.dromara.facility.domain.dto.geojson.FacGeoJsonByPlane;
|
||||||
|
import org.dromara.facility.domain.dto.geojson.FacGeoJsonByPoint;
|
||||||
import org.dromara.facility.domain.dto.photovoltaicpanel.FacPhotovoltaicPanelCreateByGeoJsonReq;
|
import org.dromara.facility.domain.dto.photovoltaicpanel.FacPhotovoltaicPanelCreateByGeoJsonReq;
|
||||||
import org.dromara.facility.domain.dto.photovoltaicpanel.FacPhotovoltaicPanelCreateReq;
|
import org.dromara.facility.domain.dto.photovoltaicpanel.FacPhotovoltaicPanelCreateReq;
|
||||||
import org.dromara.facility.domain.dto.photovoltaicpanel.FacPhotovoltaicPanelQueryReq;
|
import org.dromara.facility.domain.dto.photovoltaicpanel.FacPhotovoltaicPanelQueryReq;
|
||||||
@ -201,28 +204,30 @@ public class FacPhotovoltaicPanelServiceImpl extends ServiceImpl<FacPhotovoltaic
|
|||||||
.in(PgsProgressCategory::getWorkType, PgsProgressCategoryConstant.PHOTOVOLTAIC_PANEL_PROGRESS_CATEGORY_WORK_TYPE).list();
|
.in(PgsProgressCategory::getWorkType, PgsProgressCategoryConstant.PHOTOVOLTAIC_PANEL_PROGRESS_CATEGORY_WORK_TYPE).list();
|
||||||
Map<Long, List<PgsProgressCategory>> progressCategoryMap = progressCategoryList.stream()
|
Map<Long, List<PgsProgressCategory>> progressCategoryMap = progressCategoryList.stream()
|
||||||
.collect(Collectors.groupingBy(PgsProgressCategory::getMatrixId));
|
.collect(Collectors.groupingBy(PgsProgressCategory::getMatrixId));
|
||||||
ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
|
|
||||||
List<FacPhotovoltaicPanel> allPanels = new ArrayList<>();
|
List<FacPhotovoltaicPanel> allPanels = new ArrayList<>();
|
||||||
try {
|
List<Future<List<FacPhotovoltaicPanel>>> futures = new ArrayList<>();
|
||||||
List<Future<List<FacPhotovoltaicPanel>>> futures = new ArrayList<>();
|
Long userId = LoginHelper.getUserId();
|
||||||
Long userId = LoginHelper.getUserId();
|
// 构建光伏板实体集合
|
||||||
for (FacFeatureByPlane locationFeature : locationFeatures) {
|
try (ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors())) {
|
||||||
|
for (FacFeatureByPoint nameFeature : nameFeatures) {
|
||||||
Future<List<FacPhotovoltaicPanel>> future = executorService.submit(() -> {
|
Future<List<FacPhotovoltaicPanel>> future = executorService.submit(() -> {
|
||||||
List<FacPhotovoltaicPanel> panelList = new ArrayList<>();
|
List<FacPhotovoltaicPanel> panelList = new ArrayList<>();
|
||||||
// ① 获取 geometry 坐标
|
// ① 找到该点对应的 polygon(优先包含,否则最近)
|
||||||
FacGeometryByPlane geometry = locationFeature.getGeometry();
|
FacFeatureByPlane matchedPolygon = JSTUtil.findNearestOrContainingPolygon(nameFeature, locationFeatures);
|
||||||
List<List<Double>> coordinates = geometry.getCoordinates().getFirst();
|
if (matchedPolygon == null) return Collections.emptyList();
|
||||||
// ② 判断方阵
|
// ② 获取 geometry 坐标
|
||||||
|
List<List<Double>> coordinates = matchedPolygon.getGeometry().getCoordinates().getFirst();
|
||||||
|
// ③ 判断所属方阵
|
||||||
FacMatrix matrix = matrixService.getMatrixIdBy2Coordinates(matrixList, coordinates);
|
FacMatrix matrix = matrixService.getMatrixIdBy2Coordinates(matrixList, coordinates);
|
||||||
if (matrix == null) return Collections.emptyList();
|
if (matrix == null) return Collections.emptyList();
|
||||||
// ③ 获取名称
|
|
||||||
String name = JSTUtil.findNearestPointText(coordinates, nameFeatures);
|
|
||||||
if (name == null) return Collections.emptyList();
|
|
||||||
// ④ 获取进度类别
|
|
||||||
Long matrixId = matrix.getId();
|
Long matrixId = matrix.getId();
|
||||||
|
// ④ 获取进度类别
|
||||||
List<PgsProgressCategory> progressCategoryListByMatrix = progressCategoryMap.get(matrixId);
|
List<PgsProgressCategory> progressCategoryListByMatrix = progressCategoryMap.get(matrixId);
|
||||||
if (CollUtil.isEmpty(progressCategoryListByMatrix)) return Collections.emptyList();
|
if (CollUtil.isEmpty(progressCategoryListByMatrix)) return Collections.emptyList();
|
||||||
// ⑤ 构建光伏板
|
// ⑤ 获取名称
|
||||||
|
String name = nameFeature.getProperties() != null ? nameFeature.getProperties().getText() : null;
|
||||||
|
if (StringUtils.isBlank(name)) return Collections.emptyList();
|
||||||
|
// ⑥ 构建面板数据
|
||||||
for (PgsProgressCategory progressCategory : progressCategoryListByMatrix) {
|
for (PgsProgressCategory progressCategory : progressCategoryListByMatrix) {
|
||||||
FacPhotovoltaicPanel panel = new FacPhotovoltaicPanel();
|
FacPhotovoltaicPanel panel = new FacPhotovoltaicPanel();
|
||||||
panel.setMatrixId(matrixId);
|
panel.setMatrixId(matrixId);
|
||||||
@ -259,16 +264,6 @@ public class FacPhotovoltaicPanelServiceImpl extends ServiceImpl<FacPhotovoltaic
|
|||||||
log.error("线程执行异常", e);
|
log.error("线程执行异常", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
|
||||||
executorService.shutdown();
|
|
||||||
try {
|
|
||||||
if (!executorService.awaitTermination(60, TimeUnit.SECONDS)) {
|
|
||||||
executorService.shutdownNow();
|
|
||||||
}
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
executorService.shutdownNow();
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// 自定义线程池(IO 密集型线程池)
|
// 自定义线程池(IO 密集型线程池)
|
||||||
ThreadPoolExecutor customExecutor = new ThreadPoolExecutor(
|
ThreadPoolExecutor customExecutor = new ThreadPoolExecutor(
|
||||||
|
@ -3,12 +3,16 @@ package org.dromara.utils;
|
|||||||
import org.dromara.common.core.constant.HttpStatus;
|
import org.dromara.common.core.constant.HttpStatus;
|
||||||
import org.dromara.common.core.exception.ServiceException;
|
import org.dromara.common.core.exception.ServiceException;
|
||||||
import org.dromara.constant.GeoJsonConstant;
|
import org.dromara.constant.GeoJsonConstant;
|
||||||
|
import org.dromara.facility.domain.dto.geojson.FacFeatureByPlane;
|
||||||
import org.dromara.facility.domain.dto.geojson.FacFeatureByPoint;
|
import org.dromara.facility.domain.dto.geojson.FacFeatureByPoint;
|
||||||
import org.dromara.facility.domain.dto.geojson.FacGeometry;
|
import org.dromara.facility.domain.dto.geojson.FacGeometry;
|
||||||
import org.dromara.facility.domain.dto.geojson.FacGeometryByPoint;
|
import org.dromara.facility.domain.dto.geojson.FacGeometryByPoint;
|
||||||
import org.locationtech.jts.geom.*;
|
import org.locationtech.jts.geom.*;
|
||||||
|
import org.locationtech.jts.index.strtree.STRtree;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -185,24 +189,79 @@ public class JSTUtil {
|
|||||||
.map(coord -> new Coordinate(coord.getFirst(), coord.get(1)))
|
.map(coord -> new Coordinate(coord.getFirst(), coord.get(1)))
|
||||||
.toArray(Coordinate[]::new);
|
.toArray(Coordinate[]::new);
|
||||||
Polygon jtsPolygon = geometryFactory.createPolygon(polygonCoords);
|
Polygon jtsPolygon = geometryFactory.createPolygon(polygonCoords);
|
||||||
// 2. 查找最近点
|
// 2. 构建空间索引(JTS STRtree)
|
||||||
FacFeatureByPoint nearestFeature = null;
|
STRtree spatialIndex = new STRtree();
|
||||||
double minDistance = Double.MAX_VALUE;
|
Map<Coordinate, FacFeatureByPoint> coordToFeatureMap = new HashMap<>();
|
||||||
for (FacFeatureByPoint feature : points) {
|
for (FacFeatureByPoint feature : points) {
|
||||||
List<Double> coords = feature.getGeometry().getCoordinates();
|
List<Double> coords = feature.getGeometry().getCoordinates();
|
||||||
if (coords == null || coords.size() != 2) continue;
|
if (coords == null || coords.size() != 2) continue;
|
||||||
Point point = geometryFactory.createPoint(new Coordinate(coords.get(0), coords.get(1)));
|
Coordinate coord = new Coordinate(coords.get(0), coords.get(1));
|
||||||
|
Point point = geometryFactory.createPoint(coord);
|
||||||
|
// 用点的 Envelope 加入索引
|
||||||
|
spatialIndex.insert(point.getEnvelopeInternal(), point);
|
||||||
|
coordToFeatureMap.put(coord, feature);
|
||||||
|
}
|
||||||
|
// 3. 查询距离 polygon 最近的点
|
||||||
|
// 用 polygon 中心点附近构造 Envelope(扩大一些范围)
|
||||||
|
Envelope searchEnv = jtsPolygon.getEnvelopeInternal();
|
||||||
|
searchEnv.expandBy(10); // 扩大搜索半径
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
List<Point> candidatePoints = spatialIndex.query(searchEnv);
|
||||||
|
double minDistance = Double.MAX_VALUE;
|
||||||
|
Coordinate nearestCoord = null;
|
||||||
|
for (Point point : candidatePoints) {
|
||||||
double distance = point.distance(jtsPolygon);
|
double distance = point.distance(jtsPolygon);
|
||||||
if (distance < minDistance) {
|
if (distance < minDistance) {
|
||||||
minDistance = distance;
|
minDistance = distance;
|
||||||
nearestFeature = feature;
|
nearestCoord = point.getCoordinate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 3. 返回最近点的 text
|
if (nearestCoord != null) {
|
||||||
if (nearestFeature != null && nearestFeature.getProperties() != null) {
|
FacFeatureByPoint nearestFeature = coordToFeatureMap.get(nearestCoord);
|
||||||
return nearestFeature.getProperties().getText();
|
if (nearestFeature != null && nearestFeature.getProperties() != null) {
|
||||||
|
return nearestFeature.getProperties().getText();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 匹配最近的面,获取该面的信息
|
||||||
|
*
|
||||||
|
* @param pointFeature 点位
|
||||||
|
* @param polygons 平面列表
|
||||||
|
* @return 最近面的信息
|
||||||
|
*/
|
||||||
|
public static FacFeatureByPlane findNearestOrContainingPolygon(
|
||||||
|
FacFeatureByPoint pointFeature,
|
||||||
|
List<FacFeatureByPlane> polygons
|
||||||
|
) {
|
||||||
|
if (pointFeature == null || polygons == null || polygons.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
List<Double> coords = pointFeature.getGeometry().getCoordinates();
|
||||||
|
if (coords == null || coords.size() != 2) return null;
|
||||||
|
Coordinate pointCoord = new Coordinate(coords.get(0), coords.get(1));
|
||||||
|
Point point = geometryFactory.createPoint(pointCoord);
|
||||||
|
FacFeatureByPlane nearestPolygon = null;
|
||||||
|
double minDistance = Double.MAX_VALUE;
|
||||||
|
for (FacFeatureByPlane polygonFeature : polygons) {
|
||||||
|
List<List<Double>> polyCoords = polygonFeature.getGeometry().getCoordinates().getFirst();
|
||||||
|
Coordinate[] polygonCoords = polyCoords.stream()
|
||||||
|
.map(c -> new Coordinate(c.getFirst(), c.get(1)))
|
||||||
|
.toArray(Coordinate[]::new);
|
||||||
|
Polygon polygon = geometryFactory.createPolygon(polygonCoords);
|
||||||
|
// 优先使用包含点的 polygon
|
||||||
|
if (polygon.contains(point)) {
|
||||||
|
return polygonFeature;
|
||||||
|
}
|
||||||
|
double distance = polygon.distance(point);
|
||||||
|
if (distance < minDistance) {
|
||||||
|
minDistance = distance;
|
||||||
|
nearestPolygon = polygonFeature;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nearestPolygon;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user