In Mapbox.js, how to smooth a polyline?

不打扰是莪最后的温柔 提交于 2020-01-04 13:26:39

问题


The code can be viewed at

http://jsfiddle.net/qsr5bs6v/

Following are the lines to add a polyline

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

As can be seen, there is an angle in the joint point of every two lines belonging to the polyline, like this, which is not so attractive:

I was wondering whether there is an easy way to make the angle into a rounded curve in Mapbox..

(I saw this post about smoothing a polyline Smooth polyline with minimal deformation . In that post, I saw CHAIKIN'S ALGORITHMS is suggested but the drawback of that algorithm is that the smoothed curve doesn't pass directly through the control points... )


回答1:


You can use turf-bezier to create an interpolated bezier line out of any LineString geometry.




回答2:


You should get a string geometry that can be converted to an array of coordinates

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;

}




回答3:


In my case, linejoin option was unnoticeable and bezier curves alter path too much. Inspired by this solution, I've created custom points-To-Path method for Leaflet to smooth path corners in L.polyline. I am sure this can be easily adapted to Mapbox.

Note: this method was tested only with polylines and does not expect closed path.

example: https://jsfiddle.net/v51amucr/

Result:

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


来源:https://stackoverflow.com/questions/29074956/in-mapbox-js-how-to-smooth-a-polyline

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!