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

In Mapbox.js, how to smooth a polyline?

代码可以在

查看

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)

可以看出,属于折线的每两条线的连接点都有一个角度,像这样,不太好看:

我想知道有没有简单的方法可以在 Mapbox 中将角度变成圆角曲线..

(我看到这个 post 关于平滑折线 Smooth polyline with minimal deformation 。在那 post 中,我看到建议使用 CHAIKIN 算法,但该算法的缺点是平滑曲线不'直接通过控制点...)

您可以使用 turf-bezier 从任何 LineString 几何图形创建内插贝塞尔线。

您应该得到一个可以转换为坐标数组的字符串几何图形

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;

}

在我的例子中,linejoin 选项不明显,贝塞尔曲线改变路径太多。 受 this 解决方案的启发,我为 Leaflet 创建了自定义点到路径方法,以平滑 L.polyline 中的路径角。我相信这可以很容易地适应 Mapbox。

注意:此方法仅使用多段线进行测试,不需要闭合路径。

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

结果:

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"
  );
};