В Mapbox.js, как сгладить ломаную линию?
Код можно посмотреть на
Ниже приведены строки для добавления полилинии.
L.polyline([[31.233, 121.465], [31.233499, 121.500634], [31.190172, 121.588107]], {
color: '#000',
smoothFactor: 10.0
}).addTo(map)
Как можно видеть, в точке соединения каждых двух линий, принадлежащих ломаной линии, есть угол, который выглядит не так привлекательно:
Мне было интересно, есть ли простой способ сделать угол в закругленной кривой в Mapbox..
(Я видел этот пост о сглаживании ломаной линии. Гладкая ломаная с минимальной деформацией. В этом посте я видел предложенные алгоритмы CHAIKIN, но недостатком этого алгоритма является то, что сглаженная кривая не проходит непосредственно через контрольные точки...)
2 ответа
Вы можете использовать Turf-Bezier для создания интерполированной линии Безье из любой геометрии LineString.
В моем случае, linejoin
вариант был незаметен, а кривые Безье слишком сильно меняли путь. Вдохновленный этим решением, я создал собственный метод points-To-Path для 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"
);
};
Вы должны получить геометрию строки, которая может быть преобразована в массив координат
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;
}