在Mapbox.js中,如何平滑多段线?
In Mapbox.js, how to smooth a polyline?
代码可以在
查看
以下是添加折线的行
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"
);
};
代码可以在
查看以下是添加折线的行
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"
);
};