在Mapbox.js中,如何平滑折线?

时间:2015-03-16 10:48:31

标签: javascript geometry leaflet mapbox

可以在

查看代码

http://jsfiddle.net/qsr5bs6v/

以下是添加折线的行

L.polyline([[31.233, 121.465], [31.233499, 121.500634], [31.190172, 121.588107]], {
    color: '#000',
    smoothFactor: 10.0
}).addTo(map)

可以看出,属于折线的每两条线的关节点都有一个角度,就像这样,不太吸引人:

enter image description here

我想知道是否有一种简单的方法可以将角度变成Mapbox中的圆形曲线。

(我看过这篇关于平滑折线Smooth polyline with minimal deformation的文章。在那篇文章中,我看到了CHAIKIN的算法,但该算法的缺点是平滑的曲线不能直接通过控制点。 。)

3 个答案:

答案 0 :(得分:4)

您可以使用turf-bezier从任何LineString几何体中创建插值贝塞尔曲线。

答案 1 :(得分:0)

您应该获得可以转换为坐标数组的字符串几何形状

function decode(str) {
var flag = true;
setTimeout(() => { flag = false; return []; }, 3000);
var index = 0,
  lat = 0,
  lng = 0,
  coordinates = [],
  shift = 0,
  result = 0,
  byte = null,
  latitude_change,
  longitude_change,
  factor = Math.pow(10, 6);
while (flag && index < str.length) {
  byte = null;
  shift = 0;
  result = 0;
  do {
    byte = str.charCodeAt(index++) - 63;
    result |= (byte & 0x1f) << shift;
    shift += 5;
  } while (flag && byte >= 0x20);
  latitude_change = ((result & 1) ? ~(result >> 1) : (result >> 1));
  shift = result = 0;
  do {
    byte = str.charCodeAt(index++) - 63;
    result |= (byte & 0x1f) << shift;
    shift += 5;
  } while (flag && byte >= 0x20);
  longitude_change = ((result & 1) ? ~(result >> 1) : (result >> 1));
  lat += latitude_change;
  lng += longitude_change;
  coordinates.push([lat / factor, lng / factor]);
}
return coordinates;

}

答案 2 :(得分:0)

在我的情况下,linejoin选项不明显,贝塞尔曲线对路径的改变太大。 受this解决方案的启发,我为Leaflet创建了自定义的指向路径的方法,以平滑L.polyline中的路径角。我相信这可以轻松地适应Mapbox。

注意:此方法仅通过折线进行了测试,不希望使用闭合路径。

示例:https://jsfiddle.net/v51amucr/

结果:

example smooth polyline

function roundPathCorners(rings, radius) {
  function moveTowardsFractional(movingPoint, targetPoint, fraction) {
    return {
      x: movingPoint.x + (targetPoint.x - movingPoint.x) * fraction,
      y: movingPoint.y + (targetPoint.y - movingPoint.y) * fraction
    };
  }

  function pointForCommand(cmd) {
    return {
      x: parseFloat(cmd[cmd.length - 2]),
      y: parseFloat(cmd[cmd.length - 1])
    };
  }

  var resultCommands = [];
  if (+radius) {
  // negative numbers create artifacts
    radius = Math.abs(radius);
  } else {
    radius = 0.15;
  }

  for (i = 0, len = rings.length; i < len; i++) {
    commands = rings[i];
    // start point    
    resultCommands.push(["M", commands[0].x, commands[0].y]);

    for (var cmdIndex = 1; cmdIndex < commands.length; cmdIndex++) {
      var prevCmd = resultCommands[resultCommands.length - 1];
      var curCmd = commands[cmdIndex];
      var nextCmd = commands[cmdIndex + 1];

      if (nextCmd && prevCmd) {
        // Calc the points we're dealing with
        var prevPoint = pointForCommand(prevCmd); // convert to Object
        var curPoint = curCmd;
        var nextPoint = nextCmd;

        // The start and end of the cuve are just our point moved towards the previous and next points, respectivly
        var curveStart, curveEnd;

        curveStart = moveTowardsFractional(
          curPoint,
          prevCmd.origPoint || prevPoint,
          radius
        );
        curveEnd = moveTowardsFractional(
          curPoint,
          nextCmd.origPoint || nextPoint,
          radius
        );

        // Adjust the current command and add it
        curCmd = Object.values(curveStart);

        curCmd.origPoint = curPoint;
        curCmd.unshift("L");
        resultCommands.push(curCmd);

        // The curve control points are halfway between the start/end of the curve and
        // calculate curve, if radius is different than 0
        if (radius) {
          var startControl = moveTowardsFractional(curveStart, curPoint, 0.5);
          var endControl = moveTowardsFractional(curPoint, curveEnd, 0.5);
          // Create the curve
          var curveCmd = [
            "C",
            startControl.x,
            startControl.y,
            endControl.x,
            endControl.y,
            curveEnd.x,
            curveEnd.y
          ];
          // Save the original point for fractional calculations
          curveCmd.origPoint = curPoint;
          resultCommands.push(curveCmd);
        }
      } else {
        // Pass through commands that don't qualify
        var el = Object.values(curCmd);
        el.unshift("L");
        resultCommands.push(el);
      }
    }
  }

  return (
    resultCommands.reduce(function(str, c) {
      return str + c.join(" ") + " ";
    }, "") || "M0 0"
  );
};