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.components.AsyncResultManager;
import com.shkpr.service.alambizplugin.constants.GisSurveySystemCheckKeys;
import com.shkpr.service.alambizplugin.constants.GisSurveySystemCheckResultHead;
import com.shkpr.service.alambizplugin.constants.LogFlagBusiType;
import com.shkpr.service.alambizplugin.dto.GisSurveyLayerApplyLine;
import com.shkpr.service.alambizplugin.dto.GisSurveySystemCheckElement;
import com.shkpr.service.alambizplugin.dto.GisSurveySystemCheckId;
import com.shkpr.service.alambizplugin.dto.GisSurveySystemCheckResultDetail;
import org.locationtech.jts.geom.LineString;
import org.locationtech.jts.index.strtree.STRtree;
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.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
/**
* 交叉线差寻找器
*
* @author 欧阳劲驰
* @since 1.0.0
*/
@Component
public class CrossLinesFinder {
/**
* log
*/
private final String mStrClassName;
private final String mBizType;
private final AsyncResultManager asyncResultManager;
public CrossLinesFinder(AsyncResultManager asyncResultManager) {
mStrClassName = "OverlapLinesFinder";
mBizType = LogFlagBusiType.BUSI_GIS_SURVEY.toStrValue();
this.asyncResultManager = asyncResultManager;
}
/**
* 寻找交叉线
*
返回的为交叉线组,未交叉的线不会出现在返回结果
* 一组线,仅为两条交叉的线,长度固定为2
*
* @param lines 线集合
* @return 交叉线分组
*/
@Async
public ListenableFuture findCrossLines(List lines
, GisSurveySystemCheckId systemCheckId) throws InterruptedException {
LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName, "开始执行寻找重叠线========>");
long begin = System.currentTimeMillis();
//创建空间索引
STRtree tree = new STRtree();
//元素存入索引
for (GisSurveyLayerApplyLine layerApplyLine : lines) {
if (layerApplyLine.getGis() == null) continue;
LineString line = layerApplyLine.getGis();
tree.insert(line.getEnvelopeInternal(), layerApplyLine);
}
tree.build();
//结果
List> groupElements = new ArrayList<>();
//处理过的code
Set processedCodes = new HashSet<>();
//遍历所有线
for (GisSurveyLayerApplyLine line1 : lines) {
if (line1.getGis() == null) continue;
//响应中断
if (Thread.interrupted()) throw new InterruptedException();
//查询索引内元素
List> candidates = tree.query(line1.getGis().getEnvelopeInternal());
for (Object obj : candidates) {
GisSurveyLayerApplyLine line2 = (GisSurveyLayerApplyLine) obj;
//排除code相同或已经处理的元素,
if (Objects.equals(line1.getCode(), line2.getCode())
|| processedCodes.contains(line2.getCode())
|| line2.getGis() == null
) continue;
//响应中断
if (Thread.interrupted()) throw new InterruptedException();
// 判断是否交叉
if (line1.getGis().crosses(line2.getGis())) {
//创建两两一组交叉线对
groupElements.add(Arrays.asList(
BeanUtil.copy(line1, GisSurveySystemCheckElement.class),
BeanUtil.copy(line2, GisSurveySystemCheckElement.class)
));
}
}
//存入code,避免重复处理
processedCodes.add(line1.getCode());
}
return new AsyncResult<>(createResult(groupElements, systemCheckId, begin));
}
/**
* 创建结果
*
* @param data 数据
* @param systemCheckId 系统检查id
* @param begin 开始时间
* @return 结果
*/
private GisSurveySystemCheckResultDetail createResult(List> data
, GisSurveySystemCheckId systemCheckId, long begin) {
//数据大小
final int size = data.size();
//结果flag
final String FLAG = systemCheckId.getFlag();
//写入json和excel结果
Path jsonPath = asyncResultManager.writeJson(data, FLAG, GisSurveySystemCheckKeys.CROSS_LINES + ".json");
Path excelPath = asyncResultManager.writeExcel(GisSurveySystemCheckResultHead.CROSS_LINES,
buildExcel(data), FLAG, GisSurveySystemCheckKeys.CROSS_LINES + ".xlsx");
long end = System.currentTimeMillis();
LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName
, String.format(
"结束执行寻找交叉线,用时(毫秒):%d"
, (end - begin)
)
);
//构建结果
return new GisSurveySystemCheckResultDetail(true
, FLAG + "/" + jsonPath.getFileName()
, FLAG + "/" + excelPath.getFileName()
, size);
}
/**
* 构建excel数据
*
* @param data 数据
* @return excel数据
*/
private List