package com.shkpr.service.alambizplugin.components.checker;
import com.global.base.log.LogLevelFlag;
import com.global.base.log.LogPrintMgr;
import com.shkpr.service.alambizplugin.commtools.BeanUtil;
import com.shkpr.service.alambizplugin.constants.LogFlagBusiType;
import com.shkpr.service.alambizplugin.dto.GisSurveyCheckElement;
import com.shkpr.service.alambizplugin.dto.GisSurveyLayerApplyPoint;
import com.shkpr.service.alambizplugin.dto.TypeDefine;
import org.apache.commons.lang3.StringUtils;
import org.locationtech.jts.geom.Coordinate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Component;
import org.springframework.util.concurrent.ListenableFuture;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 重复点寻找器
*/
@Component
public class DuplicatePointsFinder {
/**
* 经纬度默认精度
*/
private final static int DEFAULT_SCALE = 6;
/**
* 经度key
*/
private final static String LNG_KEY = "lng";
/**
* 纬度key
*/
private final static String LAT_KEY = "lat";
/**
* log
*/
private final String mStrClassName;
private final String mBizType;
public DuplicatePointsFinder() {
mStrClassName = "DuplicatePointsFinder";
mBizType = LogFlagBusiType.BUSI_GIS_SURVEY.toStrValue();
}
/**
* 寻找重复点
*
根据 精度 强匹配
*
* @param points 点集合
* @param typeDefines 类型定义
* @return 重复点
*/
@Async
public ListenableFuture>> findDuplicatePoints(List points, List typeDefines) throws InterruptedException {
//经纬度精度
int lonScale = getScale(typeDefines, LNG_KEY);
int latScale = getScale(typeDefines, LAT_KEY);
LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName,
String.format("开始执行寻找重复点 经度精度:%s 纬度精度:%s ======>", lonScale, latScale));
long begin = System.currentTimeMillis();
//根据经纬度分组
Map> keyToPoints = points.parallelStream()
.collect(Collectors.groupingBy(point -> {
//抹去经纬度精度,并设置为分组条件
Coordinate coordinate = point.getGis().getCoordinate();
BigDecimal bdLon = new BigDecimal(Double.toString(coordinate.getX())).setScale(lonScale, RoundingMode.DOWN);
BigDecimal bdLat = new BigDecimal(Double.toString(coordinate.getY())).setScale(latScale, RoundingMode.DOWN);
return String.format("%s%s%s", bdLon.toPlainString(), bdLat.toPlainString(), point.getElevation());
}, Collectors.toList()));
//响应中断
if (Thread.interrupted()) throw new InterruptedException();
//并行流处理
List> collect = keyToPoints.values().parallelStream()
//过滤组内大于1
.filter(group -> group.size() > 1)
//转为返回元素
.map(group -> group.stream()
.map(point-> BeanUtil.copy(point, GisSurveyCheckElement.class))
.collect(Collectors.toList())
)
.collect(Collectors.toList());
long end = System.currentTimeMillis();
LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName
, String.format(
"结束执行寻找重复点,用时(毫秒):%d"
, (end - begin)
)
);
return new AsyncResult<>(collect);
}
/**
* 获取精度
*
* @param typeDefines 类型定义
* @param key 类型定义key
* @return 经度精度
*/
private int getScale(List typeDefines, String key) {
//空返回默认值
if (typeDefines == null || typeDefines.isEmpty()) return DEFAULT_SCALE;
//过滤出纬度类型定义
TypeDefine typeDefine = typeDefines.stream()
.filter(td -> key.equals(td.getKey()))
.findFirst()
.orElse(null);
//解析参数而,转换成数字,大于等于0则使用字典
if (typeDefine != null && StringUtils.isNotBlank(typeDefine.getParam2())) {
try {
int lngScale = Integer.parseInt(typeDefine.getParam2());
return lngScale < 0 ? DEFAULT_SCALE : lngScale;
} catch (NumberFormatException e) {
return DEFAULT_SCALE;
}
}
return DEFAULT_SCALE;
}
}