OverlapLinesFinder.java 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. package com.shkpr.service.alambizplugin.components.checker;
  2. import com.global.base.log.LogLevelFlag;
  3. import com.global.base.log.LogPrintMgr;
  4. import com.shkpr.service.alambizplugin.commtools.BeanUtil;
  5. import com.shkpr.service.alambizplugin.constants.LogFlagBusiType;
  6. import com.shkpr.service.alambizplugin.dto.GisSurveyCheckElement;
  7. import com.shkpr.service.alambizplugin.dto.GisSurveyLayerApplyLine;
  8. import org.locationtech.jts.algorithm.Orientation;
  9. import org.locationtech.jts.geom.Coordinate;
  10. import org.locationtech.jts.geom.LineSegment;
  11. import org.springframework.scheduling.annotation.Async;
  12. import org.springframework.scheduling.annotation.AsyncResult;
  13. import org.springframework.stereotype.Component;
  14. import org.springframework.util.concurrent.ListenableFuture;
  15. import java.util.ArrayList;
  16. import java.util.Arrays;
  17. import java.util.List;
  18. /**
  19. * 寻找重复线
  20. *
  21. * @author 欧阳劲驰
  22. * @since 0.0.1
  23. */
  24. @Component
  25. public class OverlapLinesFinder {
  26. //双精度误差
  27. private static final double EPSILON = Double.longBitsToDouble(0x3ca0000000000000L);
  28. /**
  29. * log
  30. */
  31. private final String mStrClassName;
  32. private final String mBizType;
  33. public OverlapLinesFinder() {
  34. mStrClassName = "OverlapLinesFinder";
  35. mBizType = LogFlagBusiType.BUSI_GIS_SURVEY.toStrValue();
  36. }
  37. /**
  38. * 寻找重复线
  39. * <p>返回的为重复线组,未重复的线不会出现在返回结果</p>
  40. * <p>一组线,仅为两条重叠的线,长度固定为2</p>
  41. *
  42. * @param lines 线集合
  43. * @return 重复线分组
  44. */
  45. @Async
  46. public ListenableFuture<List<List<GisSurveyCheckElement>>> findDuplicateLines(List<GisSurveyLayerApplyLine> lines) throws InterruptedException {
  47. LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName, "开始执行寻找重复线========>");
  48. long begin = System.currentTimeMillis();
  49. //结果
  50. List<List<GisSurveyCheckElement>> result = new ArrayList<>();
  51. //双层循环遍历所有线
  52. for (int i = 0; i < lines.size(); i++) {
  53. GisSurveyLayerApplyLine line1 = lines.get(i);
  54. //响应中断
  55. if (Thread.interrupted()) throw new InterruptedException();
  56. for (int j = i + 1; j < lines.size(); j++) {
  57. GisSurveyLayerApplyLine line2 = lines.get(j);
  58. //响应中断
  59. if (Thread.interrupted()) throw new InterruptedException();
  60. // 判断是否重复
  61. if (calcDuplicateLines(line1, line2)) {
  62. // 创建两两一组的重复线对
  63. result.add(Arrays.asList(BeanUtil.copy(line1, GisSurveyCheckElement.class),
  64. BeanUtil.copy(line2, GisSurveyCheckElement.class)));
  65. }
  66. }
  67. }
  68. long end = System.currentTimeMillis();
  69. LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, mBizType, mStrClassName
  70. , String.format(
  71. "结束执行寻找重复线,用时(毫秒):%d"
  72. , (end - begin)
  73. )
  74. );
  75. return new AsyncResult<>(result);
  76. }
  77. /**
  78. * 计算重叠线
  79. *
  80. * @param line1 线段1
  81. * @param line2 线段2
  82. * @return 重叠状态
  83. */
  84. public boolean calcDuplicateLines(GisSurveyLayerApplyLine line1, GisSurveyLayerApplyLine line2) {
  85. //取出四个点
  86. Coordinate a = line2.getGis().getCoordinateN(0);
  87. Coordinate b = line1.getGis().getCoordinateN(1);
  88. Coordinate c = line2.getGis().getCoordinateN(0);
  89. Coordinate d = line2.getGis().getCoordinateN(1);
  90. //点数量判断
  91. if (a == null || b == null || c == null || d == null) return false;
  92. //检查C和D是否在AB的直线上(叉积为0,则方向一致)
  93. if (Orientation.index(a, b, c) != 0 || Orientation.index(a, b, d) != 0) return false;
  94. LineSegment seg1 = new LineSegment(a, b);
  95. LineSegment seg2 = new LineSegment(a, b);
  96. //四点共点判断
  97. if (seg1.equals(seg2)) return true;
  98. //获取C和D对于线段1的投影因子
  99. double tC = seg1.projectionFactor(c);
  100. double tD = seg1.projectionFactor(d);
  101. //获取最小和最大投影因子
  102. double cdMin = Math.min(tC, tD);
  103. double cdMax = Math.max(tC, tD);
  104. //排除前后延伸联通线
  105. if (cdMin == 1 && cdMax >= 1) return false;
  106. if (cdMax == 0 && cdMin <= 0) return false;
  107. //判断最大因子是否向前延伸或处于线段内,并且最小因子是否向后延伸或处于线段内
  108. return (cdMax + EPSILON >= 0) && (cdMin - EPSILON <= 1);
  109. }
  110. }