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.GisSurveyLayerApplyLine;
import org.locationtech.jts.algorithm.Orientation;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.LineSegment;
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.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* 寻找重复线
*
* @author 欧阳劲驰
* @since 0.0.1
*/
@Component
public class OverlapLinesFinder {
//双精度误差
private static final double EPSILON = Double.longBitsToDouble(0x3ca0000000000000L);
/**
* log
*/
private final String mStrClassName;
private final String mBizType;
public OverlapLinesFinder() {
mStrClassName = "OverlapLinesFinder";
mBizType = LogFlagBusiType.BUSI_GIS_SURVEY.toStrValue();
}
/**
* 寻找重复线
*
返回的为重复线组,未重复的线不会出现在返回结果
* 一组线,仅为两条重叠的线,长度固定为2
*
* @param lines 线集合
* @return 重复线分组
*/
@Async
public ListenableFuture>> findDuplicateLines(List lines) throws InterruptedException {
LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName, "开始执行寻找重复线========>");
long begin = System.currentTimeMillis();
//结果
List> result = new ArrayList<>();
//双层循环遍历所有线
for (int i = 0; i < lines.size(); i++) {
GisSurveyLayerApplyLine line1 = lines.get(i);
//响应中断
if (Thread.interrupted()) throw new InterruptedException();
for (int j = i + 1; j < lines.size(); j++) {
GisSurveyLayerApplyLine line2 = lines.get(j);
//响应中断
if (Thread.interrupted()) throw new InterruptedException();
// 判断是否重复
if (calcDuplicateLines(line1, line2)) {
// 创建两两一组的重复线对
result.add(Arrays.asList(BeanUtil.copy(line1, GisSurveyCheckElement.class),
BeanUtil.copy(line2, GisSurveyCheckElement.class)));
}
}
}
long end = System.currentTimeMillis();
LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName
, String.format(
"结束执行寻找重复线,用时(毫秒):%d"
, (end - begin)
)
);
return new AsyncResult<>(result);
}
/**
* 计算重叠线
*
* @param line1 线段1
* @param line2 线段2
* @return 重叠状态
*/
public boolean calcDuplicateLines(GisSurveyLayerApplyLine line1, GisSurveyLayerApplyLine line2) {
//取出四个点
Coordinate a = line2.getGis().getCoordinateN(0);
Coordinate b = line1.getGis().getCoordinateN(1);
Coordinate c = line2.getGis().getCoordinateN(0);
Coordinate d = line2.getGis().getCoordinateN(1);
//点数量判断
if (a == null || b == null || c == null || d == null) return false;
//检查C和D是否在AB的直线上(叉积为0,则方向一致)
if (Orientation.index(a, b, c) != 0 || Orientation.index(a, b, d) != 0) return false;
LineSegment seg1 = new LineSegment(a, b);
LineSegment seg2 = new LineSegment(a, b);
//四点共点判断
if (seg1.equals(seg2)) return true;
//获取C和D对于线段1的投影因子
double tC = seg1.projectionFactor(c);
double tD = seg1.projectionFactor(d);
//获取最小和最大投影因子
double cdMin = Math.min(tC, tD);
double cdMax = Math.max(tC, tD);
//排除前后延伸联通线
if (cdMin == 1 && cdMax >= 1) return false;
if (cdMax == 0 && cdMin <= 0) return false;
//判断最大因子是否向前延伸或处于线段内,并且最小因子是否向后延伸或处于线段内
return (cdMax + EPSILON >= 0) && (cdMin - EPSILON <= 1);
}
}