查找闭合线条和非闭合线条
作者:秋了秋 发表时间:2018年08月29日
如果你有这样的场景:
- 1.在一堆的线段或者折线段内找出闭合折线段或者闭合边框。
- 2.把端点相连(相距安全距离之内)的多个线段合成一条折线段。
- 3.合成后的线段基础上闭合边框和非闭合边框进行分类。
- 4.收集它们的坐标信息加以利用。
那么你要好好看这篇文章,这篇文章专门解决了上述所有问题。
/* * 【寻找闭合边框】by 秋叶博客 //netblog.cn/blog/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.netblog.site/查找闭合边框.html
8
文章作者: “秋了秋”个人博客,本站鼓励原创。
转载请注明本文地址:http://netblog.cn/blog/497.html