当前位置:秋叶网络博客 前端编程 ◊ 查找闭合线条和非闭合线条

查找闭合线条和非闭合线条

作者:秋叶 发表时间:2018年8月29日

如果你有这样的场景:

  • 1.在一堆的线段或者折线段内找出闭合折线段或者闭合边框。
  • 2.把端点相连(相距安全距离之内)的多个线段合成一条折线段。
  • 3.合成后的线段基础上闭合边框和非闭合边框进行分类。
  • 4.收集它们的坐标信息加以利用。

那么你要好好看这篇文章,这篇文章专门解决了上述所有问题。

/*
* 【寻找闭合边框】by 秋叶博客 http://www.mizuiren.com/497.html
* linesPoints可以是线条坐标点集[[{x:1,y:2},{x:2,y:3}],[{x:4,y:2},{x:6,y:7},{x:4,y:2}]]
* linesPoints也可以是线条的dom对象集合[document.querySelectorAll('polyline/line')];
* tolerance:安全间距
* */
function findCloseLine(linesPoints, tolerance) {
   var pointArrs = linesPoints;
   tolerance = tolerance || 0;//间隔,两个点相距多远以内算可以连接
   if (!Array.isArray(linesPoints[0])) {//如果数组元素不是个对象就按照dom对象来处理
      pointArrs = [];
      if(!Array.isArray(linesPoints )) {//如果是个dom集合,要把它转成数组
         linesPoints = [].slice.call(linesPoints);
      }
      if (!tolerance) {
         tolerance = linesPoints[0].getAttribute('stroke-width');//间隔取第一条线条的宽度
      }
      var points, match, xy, xys;
      linesPoints.forEach(function (line) {//把它们的路径转成坐标对象
         points = line.getAttribute('points') || line.getAttribute('d');
         if (!points) {
            return;
         }
         match = points.match(/\-?\d+(\.\d+)?.*?\d+(\.\d+)?/g);
         xys = [];
         match.forEach(function (item) {
            xy = item.match(/(\-?\d+(\.\d+)?).*?(\-?\d+(\.\d+)?)/);
            xys.push({
               x: +xy[1],
               y: +xy[3]
            });
         });
         pointArrs.push(xys);
      });
   }
   var closed = [], hadSearchIndexs = [], notClosed = [], combinePoint = [], hadCombinePoint;
   pointArrs.forEach(function (_points, index) {
      if (getDistance(_points[0], _points[_points.length - 1]) <= tolerance) {
         closed.push(_points);
         hadSearchIndexs.push(index);
         return;
      }
      combinePoint = [];
      hadCombinePoint = findNextConect(index, _points[0], 'begin');//查找线头的连接点
      if (!hadCombinePoint) {
         hadCombinePoint = findNextConect(index, _points[_points.length - 1], 'end');//查找线尾的连接点
      }
      if (hadCombinePoint) {//如果找到了连接点
         if (getDistance(hadCombinePoint[0], hadCombinePoint[hadCombinePoint.length - 1]) <= tolerance) {
            closed.push(hadCombinePoint);
         } else {
            notClosed.push(hadCombinePoint);
         }
      } else {//如果没有找到了连接点
         hadCombinePoint === '' || notClosed.push(_points);//hadCombinePoint为‘’(就是已经被连接了或当前线段)的时候不算在非闭合集合里面
      }
      hadSearchIndexs.push(index);
   });

   //拿一个端点去与其它线段的端点算距离判断是否相连,若相连把它们的坐标合并在一起组成一个完整线条
   function findNextConect(currentIndex, point, beginOrEnd) {
      var hadConected, connectPoint, currentLine, _thisLinePoints;
      var combinePoint = [];
      _infun(currentIndex, point, beginOrEnd);

      function connectAction(beginOrEnd1, beginOrEnd2, waitConnectLine, index) {
         if (beginOrEnd1 === beginOrEnd2) {
            _thisLinePoints = _thisLinePoints.reverse();
         }
         _action(beginOrEnd1, waitConnectLine);
         hadConected = true;
         hadSearchIndexs.push(index);
         _infun(currentIndex, connectPoint, beginOrEnd1);

         function isRepeatPoint(begin, end) {
            var endLastIndex = end.length - 1;
            return end[endLastIndex].x === begin[0].x && end[endLastIndex].y === begin[0].y;
         }

         function _action(beginOrEnd, waitConnectLine) {
            if (beginOrEnd === 'begin') {
               if (isRepeatPoint(waitConnectLine, _thisLinePoints)) {
                  _thisLinePoints.pop();
               }
               combinePoint = _thisLinePoints.concat(waitConnectLine);
               pointArrs[currentIndex] = combinePoint;
               connectPoint = combinePoint[0];
            } else {
               if (isRepeatPoint(_thisLinePoints, waitConnectLine)) {
                  _thisLinePoints.shift();
               }
               combinePoint = waitConnectLine.concat(_thisLinePoints);
               pointArrs[currentIndex] = combinePoint;
               connectPoint = combinePoint[combinePoint.length - 1];
            }
         }

      }

      function _infun(currentIndex, point, beginOrEnd) {
         var waitConnectLine = pointArrs[currentIndex];
         if (waitConnectLine) {
            for (var i = 0; i < pointArrs.length; i++) {
               _thisLinePoints = JSON.parse(JSON.stringify(pointArrs[i]));//克隆对象,因为后面需要删改它
               if (i === currentIndex) {
                  continue;
               }
               if (hadSearchIndexs.indexOf(currentIndex) > -1) {
                  currentLine = '';
                  continue;
               }
               if (hadSearchIndexs.indexOf(i) > -1) {
                  continue;
               }
               if (getDistance(_thisLinePoints[0], point) <= tolerance) {
                  connectAction(beginOrEnd, 'begin', waitConnectLine, i);
                  break;
               } else if (getDistance(_thisLinePoints[_thisLinePoints.length - 1], point) <= tolerance) {
                  connectAction(beginOrEnd, 'end', waitConnectLine, i);
                  break;
               }
            }
         }
      }

      if (combinePoint.length) {
         return combinePoint;
      } else {
         return currentLine;
      }
   }

   //计算两个点的距离
   function getDistance(p1, p2) {
      return Math.sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y));
   }

   var category = {//返回闭合边框和非闭合边框的分类坐标点集合
      closed: closed,
      notClosed: notClosed
   }
   return category;
}
//调用:
findCloseLine([document.querySelectorAll('polyline')], 10);

注意:

1.只支持线段和折线段的查找组合,不支持圆弧、圆、曲线的参与查找;

2.不支持两个闭合区域共线情况,如需支持,请自主融合后再查找;

3.多个多边形相交,是可以找出来,但不会融合,同2,建议先融合;

在线测试体验(按f12打开控制台查看结果):http://resource.mizuiren.com/查找闭合边框.html

转载请保留链接:查找闭合线条和非闭合线条 | 出处:秋叶个人博客| 本文链接地址:http://www.mizuiren.com/497.html
目录: 前端编程 | 标签: , | 2467次阅读