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