[update] 修改光伏板和名称匹配逻辑

This commit is contained in:
lcj
2025-06-09 19:59:39 +08:00
parent 5bb201b272
commit fbea1c2c2a
2 changed files with 87 additions and 33 deletions

View File

@ -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(

View File

@ -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;
}
} }