Arrow fix
This commit is contained in:
parent
3129ec1fea
commit
a96f4f29a9
92
MapArrow.js
92
MapArrow.js
@ -9,12 +9,7 @@ import * as turf from "@turf/turf";
|
||||
import { ARROW_BODY_STYLE_CONSTANT, ARROW_BODY_STYLE_LINEAR, ARROW_BODY_STYLE_EXPONENTIAL } from "./Arrow.js";
|
||||
|
||||
map.on('load', () => {
|
||||
const points = [
|
||||
[1.42076, 40.08804],
|
||||
[358.4050, 50.52]
|
||||
];
|
||||
|
||||
const fullPolygon = getArrowPolygon(points, 20000); // offset 20 km
|
||||
const fullPolygon = getArrowPolygon(arrowData, style, arrowHeadData);
|
||||
map.addSource("arrow-shape", { type: "geojson", data: fullPolygon });
|
||||
map.addLayer({
|
||||
id: "arrow-shape",
|
||||
@ -53,26 +48,27 @@ map.on('load', () => {
|
||||
});
|
||||
|
||||
const points = [
|
||||
{ x: 70, y: 38 },
|
||||
{ x: 71, y: 45},
|
||||
{ x: 65, y: 50 },
|
||||
{ x: 70, y: 53}
|
||||
];
|
||||
[1.42076, 40.08804],
|
||||
[15.42076, 80.08804],
|
||||
[55.42076, 75.08804],
|
||||
[120.42076, 40.08804],
|
||||
[358.4050, 50.52]
|
||||
];
|
||||
|
||||
const arrowData = {
|
||||
points: points,
|
||||
splineStep: 0.01,
|
||||
splineStep: 20,
|
||||
spacing: 0.01,
|
||||
offsetDistance: 10000
|
||||
offsetDistance: 20000
|
||||
};
|
||||
const style = {
|
||||
calculation: ARROW_BODY_STYLE_LINEAR,
|
||||
calculation: ARROW_BODY_STYLE_CONSTANT,
|
||||
range: 1,
|
||||
minValue: 0.1
|
||||
};
|
||||
const arrowHeadData = {
|
||||
widthArrow: 1,
|
||||
lengthArrow: 1
|
||||
widthArrow: 10,
|
||||
lengthArrow: 5
|
||||
};
|
||||
|
||||
// Cubic interpolation source from https://www.paulinternet.nl/?page=bicubic
|
||||
@ -98,18 +94,28 @@ function cubicInterpolate(p, x) {
|
||||
*
|
||||
* @returns {{x: number, y: number}[]} - An array of points representing the arrow polygon.
|
||||
*/
|
||||
export function getArrowPolygon(arrowData, style= undefined, arrowHeadData = undefined) {
|
||||
const splineStep = 20;
|
||||
const smooth = computeSplinePoints(arrowData.points, splineStep);
|
||||
const { leftSidePoints, rightSidePoints } = computeSideOffsets(smooth, arrowData.offsetDistance);
|
||||
export function getArrowPolygon(arrowData, style, arrowHeadData) {
|
||||
if (!style)
|
||||
style = {
|
||||
calculation: ARROW_BODY_STYLE_CONSTANT,
|
||||
range: 0,
|
||||
minValue: 0
|
||||
};
|
||||
|
||||
const end = smooth[smooth.length -1];
|
||||
const bearing = averageBearing(smooth, 3);
|
||||
const triangle = createIsoscelesTriangleCoords(turf.point(end), arrowData.offsetDistance * 5, arrowData.offsetDistance * 5, bearing);
|
||||
const splinePoints = computeSplinePoints(arrowData.points, arrowData.splineStep);
|
||||
const { leftSidePoints, rightSidePoints } = computeSideOffsets(splinePoints, arrowData.offsetDistance, style);
|
||||
|
||||
const end = splinePoints[splinePoints.length -1];
|
||||
const bearing = averageBearing(splinePoints, 3);
|
||||
const arrowHead= arrowHeadData
|
||||
? createIsoscelesTriangleCoords(
|
||||
turf.point(end),
|
||||
arrowData.offsetDistance * arrowHeadData.widthArrow, arrowData.offsetDistance * arrowHeadData.lengthArrow, bearing)
|
||||
: [];
|
||||
|
||||
const polygonCoords = [
|
||||
...leftSidePoints,
|
||||
...triangle,
|
||||
...arrowHead,
|
||||
...rightSidePoints.reverse(),
|
||||
leftSidePoints[0]
|
||||
];
|
||||
@ -125,13 +131,13 @@ function averageBearing(points, count = 3) {
|
||||
bearings.push(b);
|
||||
}
|
||||
}
|
||||
// Průměr s korekcí kruhového rozsahu
|
||||
|
||||
const sinSum = bearings.reduce((sum, b) => sum + Math.sin(b * Math.PI / 180), 0);
|
||||
const cosSum = bearings.reduce((sum, b) => sum + Math.cos(b * Math.PI / 180), 0);
|
||||
return Math.atan2(sinSum, cosSum) * 180 / Math.PI;
|
||||
}
|
||||
|
||||
function computeSplinePoints(points, segments = 10) {
|
||||
function computeSplinePoints(points, splineStep = 10) {
|
||||
if (points.length < 2) return points;
|
||||
const result = [];
|
||||
|
||||
@ -140,8 +146,8 @@ function computeSplinePoints(points, segments = 10) {
|
||||
const p1 = points[i];
|
||||
const p2 = points[i + 1];
|
||||
const p3 = points[i + 2] || p2;
|
||||
for (let j = 0; j < segments; j++) {
|
||||
const t = j / segments;
|
||||
for (let j = 0; j < splineStep; j++) {
|
||||
const t = j / splineStep;
|
||||
const lon = cubicInterpolate([p0[0], p1[0], p2[0], p3[0]], t);
|
||||
const lat = cubicInterpolate([p0[1], p1[1], p2[1], p3[1]], t);
|
||||
result.push([lon, lat]);
|
||||
@ -152,16 +158,32 @@ function computeSplinePoints(points, segments = 10) {
|
||||
return result;
|
||||
}
|
||||
|
||||
function computeSideOffsets(points, offsetMeters) {
|
||||
function computeSideOffsets(points, offsetMeters, style) {
|
||||
let leftSidePoints = [];
|
||||
let rightSidePoints = [];
|
||||
const total = points.length - 1;
|
||||
|
||||
for (let i = 1; i < points.length; i++) {
|
||||
const previousPoint = points[i - 1];
|
||||
const currentPoint = points[i];
|
||||
const bearing = turf.bearing(turf.point(previousPoint), turf.point(currentPoint));
|
||||
leftSidePoints.push(turf.destination(turf.point(currentPoint), offsetMeters, bearing - 90, { units: 'meters' }).geometry.coordinates);
|
||||
rightSidePoints.push(turf.destination(turf.point(currentPoint), offsetMeters, bearing + 90, { units: 'meters' }).geometry.coordinates);
|
||||
const normalizedPosition = i / total;
|
||||
|
||||
let localOffsetDistance;
|
||||
switch (style.calculation) {
|
||||
case ARROW_BODY_STYLE_LINEAR:
|
||||
localOffsetDistance = offsetMeters * linearWidthCurve(normalizedPosition, style.range, style.minValue);
|
||||
break;
|
||||
case ARROW_BODY_STYLE_EXPONENTIAL:
|
||||
localOffsetDistance = offsetMeters * exponentialWidthCurve(normalizedPosition, style.range, style.minValue);
|
||||
break;
|
||||
case ARROW_BODY_STYLE_CONSTANT:
|
||||
default:
|
||||
localOffsetDistance = offsetMeters;
|
||||
}
|
||||
|
||||
leftSidePoints.push(turf.destination(turf.point(currentPoint), localOffsetDistance, bearing - 90, { units: 'meters' }).geometry.coordinates);
|
||||
rightSidePoints.push(turf.destination(turf.point(currentPoint), localOffsetDistance, bearing + 90, { units: 'meters' }).geometry.coordinates);
|
||||
}
|
||||
|
||||
return { leftSidePoints, rightSidePoints };
|
||||
@ -203,3 +225,11 @@ function generateLatLonGrid(step = 10) {
|
||||
features
|
||||
};
|
||||
}
|
||||
|
||||
function exponentialWidthCurve(normalizedPosition, range = 5, minValue = 0.1) {
|
||||
return minValue + (1 - minValue) * Math.exp(-range * normalizedPosition);
|
||||
}
|
||||
|
||||
function linearWidthCurve(normalizedPosition, range = 1, minValue = 0.1) {
|
||||
return 1 + (minValue - 1) * normalizedPosition / range ;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user