d3.js如何简化复杂路径 - 使用自定义算法

时间:2014-03-19 16:40:41

标签: javascript algorithm d3.js

enter image description here

我在这里有一个非常基本的例子。 http://jsfiddle.net/jEfsh/57/创造了一条复杂的道路 - 有很多点。我已经阅读了一个算法,可以查看点并创建一个更简单的坐标集。有没有人有这方面的经验 - 关于如何循环路径数据并将其传递给算法的示例 - 找到最短的点集来创建形状的更基本版本?

http://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm

var points = "M241,59L237,60L233,60L228,61L224,61L218,63L213,63L209,65L204,66L199,67L196,68L193,69L189,70L187,72L184,72L182,74L179,75L177,76L175,78L173,79L170,81L168,83L165,85L163,87L161,89L159,92L157,95L157,97L155,102L153,105L152,110L151,113L151,117L151,123L150,137L148,180L148,185L148,189L148,193L148,197L148,202L148,206L149,212L151,218L152,222L154,229L154,232L155,235L157,239L158,241L160,245L162,247L163,249L165,251L167,254L169,256L172,258L175,260L178,261L183,265L188,268L193,270L206,273L213,275L220,275L225,275L232,276L238,277L243,277L249,277L253,277L259,277L266,277L271,277L277,277L281,277L284,277L288,277L293,277L297,276L302,274L305,272L308,271L311,268L313,267L315,264L318,261L322,257L324,254L326,249L329,244L331,241L332,239L334,234L338,230L339,226L341,222L343,218L345,213L347,211L348,207L349,201L351,196L352,192L353,187L353,183L353,180L353,178L354,176L354,173L354,170L354,168L354,167L354,166L354,164L354,162L354,161L354,159L354,158L354,155L354,152L354,149L352,143L349,137L347,133L343,125L340,119 M241,59L340,119";

d3.select("#g-1").append("path").attr("d", points);


//simplify the path

function DouglasPeucker(){

}



/*
//http://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm


function DouglasPeucker(PointList[], epsilon)
    // Find the point with the maximum distance
    dmax = 0
    index = 0
    end = length(PointList)
    for i = 2 to ( end - 1) {
        d = shortestDistanceToSegment(PointList[i], Line(PointList[1], PointList[end])) 
        if ( d > dmax ) {
            index = i
            dmax = d
        }
    }
    // If max distance is greater than epsilon, recursively simplify
    if ( dmax > epsilon ) {
        // Recursive call
        recResults1[] = DouglasPeucker(PointList[1...index], epsilon)
        recResults2[] = DouglasPeucker(PointList[index...end], epsilon)

        // Build the result list
        ResultList[] = {recResults1[1...end-1] recResults2[1...end]}
    } else {
        ResultList[] = {PointList[1], PointList[end]}
    }
    // Return the result
    return ResultList[]
end
*/

2 个答案:

答案 0 :(得分:3)

目前还不清楚你的问题究竟是什么。将SVG数据字符串转换为点列表是否有问题?你可以用这个:

function path_from_svg(svg) {
    var pts = svg.split(/[ML]/);
    var path = [];

    console.log(pts.length);
    for (var i = 1; i < pts.length; i++) {
        path.push(pts[i].split(","));
    }

    return path;
}

这是一种非常简单的方法:它在所有移动(M)和行(L)命令上拆分字符串并将它们视为行。然后它会在逗号上拆分所有子串。第一个&#34;子串&#34;被忽略,因为它是第一个M之前的空字符串。如果有办法在d3 function svg_to_path(path) { return "M" + path.join("L"); } 中做得更好,我还没有找到它。

反向操作更容易:

svg.line.interpolate("linear")

这相当于function path_simplify_r(path, first, last, eps) { if (first >= last - 1) return [path[first]]; var px = path[first][0]; var py = path[first][1]; var dx = path[last][0] - px; var dy = path[last][1] - py; var nn = Math.sqrt(dx*dx + dy*dy); var nx = -dy / nn; var ny = dx / nn; var ii = first; var max = -1; for (var i = first + 1; i < last; i++) { var p = path[i]; var qx = p[0] - px; var qy = p[1] - py; var d = Math.abs(qx * nx + qy * ny); if (d > max) { max = d; ii = i; } } if (max < eps) return [path[first]]; var p1 = path_simplify_r(path, first, ii, eps); var p2 = path_simplify_r(path, ii, last, eps); return p1.concat(p2); } function path_simplify(path, eps) { var p = path_simplify_r(path, 0, path.length - 1, eps); return p.concat([path[path.length - 1]]); }

然后,您可以递归地在此路径数据上实现Douglas-Peucker算法:

{nx, ny}

到线的距离不是在单独的函数中计算的,而是直接用第一个之间的线向量{dx, dy}上的点到第2行与正常nx*nx + ny*ny == 1的距离的公式计算最后一点。法线标准化为path[last]

创建路径时,只添加第一个点,隐含最后一个点path_simplify,必须在path_simplify_r中添加,这是递归函数p1的前端。选择此方法是为了连接左右子路径不会在中间创建重复点。 (这可以同样好,也可以通过加入p2.slice(1)和{{1}}来完成。)

这里的所有内容都放在一个小提琴中:http://jsfiddle.net/Cbk9J/3/

答案 1 :(得分:1)

对这个问题的评论中有很多好的参考资料 - 唉它们是评论,而不是可以真正投票的建议答案。

http://bost.ocks.org/mike/simplify/

显示了这种东西的交互式使用,它引用了Douglas-Peucker和Visvalingam。