2025-05-27 16:01:42 +02:00

740 lines
21 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

mapboxgl.accessToken = 'pk.eyJ1Ijoib3V0ZG9vcm1hcHBpbmdjb21wYW55IiwiYSI6ImNqYmh3cDdjYzNsMnozNGxsYzlvMmk2bTYifQ.QqcZ4LVoLWnXafXdjZxnZg';
const map = new mapboxgl.Map({
container: 'map',
center: [20, 80],
zoom: 4
});
import * as turf from "@turf/turf";
import { getArrowPolygon } from "./Arrow.js";
import { ARROW_BODY_STYLE_CONSTANT, ARROW_BODY_STYLE_LINEAR, ARROW_BODY_STYLE_EXPONENTIAL } from "./Arrow.js";
import { getCirclePolygon } from "./BasicShapes.js";
import { getRectanglePolygon } from "./BasicShapes.js";
import { getFrontline } from "./Frontline.js";
import { LEFT_SIDE, RIGHT_SIDE, BOTH_SIDES } from "./Frontline.js";
// Polygon merge using Turf library
import {mergeTurfPolygons} from "./Polygon.js";
import {addTurfPolygonToMerge} from "./Polygon.js";
import {toTurfPolygon} from "./Polygon.js";
const circleCenter = {x:320, y:180};
const circleRadius = 70;
const circleDensity = 15;
const circleCenterB = {x:400, y:280};
const circleRadiusB = 70;
const circleDensityB = 15;
const rectangleCenter= {x:100, y:300};
const rectangleSideA = 70;
const rectangleSideB = 200;
const rectangleRotation = 40;
const frontlinePointsA = [
{ x: 120, y: 400 },
{ x: 200, y: 100 },
{ x: 350, y: 200 },
{ x: 350, y: 400 },
{ x: 450, y: 480 },
{ x: 550, y: 440 },
{ x: 600, y: 300 },
];
const frontlinePointsB = [
{ x: 420, y: 280 },
{ x: 430, y: 380 },
{ x: 500, y: 400 },
{ x: 520, y: 300 },
];
const frontlinePointsC = [
{ x: 450, y: 200 },
{ x: 500, y: 250 },
{ x: 550, y: 250 },
{ x: 550, y: 200 }
];
const frontlineDataA = {
points: frontlinePointsA,
splineStep: 0.08,
spacing: 10,
offsetDistance: 10,
protrusionLength: 15,
protrusionStartSize: 5,
protrusionEndSize: 2,
protrusionGap: 20,
style: LEFT_SIDE,
};
const frontlineDataB = {
points: frontlinePointsB,
splineStep: 0.02,
spacing: 10,
offsetDistance: 10,
protrusionLength: 15,
protrusionStartSize: 5,
protrusionEndSize: 5,
protrusionGap: 20,
style: RIGHT_SIDE,
};
const frontlineDataC = {
points: frontlinePointsC,
splineStep: 0.02,
spacing: 10,
offsetDistance: 10,
protrusionLength: 15,
protrusionStartSize: 5,
protrusionEndSize: 0,
protrusionGap: 20,
style: BOTH_SIDES,
};
/*
const arrowPolygonA = getArrowPolygon(arrowDataA, styleA, arrowHeadDataA);
const arrowPolygonB = getArrowPolygon(arrowDataB, styleB, arrowHeadDataB);
const arrowPolygonC = getArrowPolygon(arrowDataC, styleC);
const circlePolygon = getCirclePolygon(circleCenter, circleRadius, circleDensity);
const circlePolygonB = getCirclePolygon(circleCenterB, circleRadiusB, circleDensityB);
const rectanglePolygon = getRectanglePolygon(rectangleCenter, rectangleSideA, rectangleSideB, rectangleRotation);
const mergedTurfPoly = mergeTurfPolygons(arrowPolygonA, arrowPolygonC);
const mergedTurfPolyAll = addTurfPolygonToMerge(mergedTurfPoly, arrowPolygonB);
const mergedTurfPolyRectangle = addTurfPolygonToMerge(mergedTurfPolyAll, rectanglePolygon);
const mergedRectangle = mergeTurfPolygons(circlePolygon, circlePolygonB);
const rectanglePoly = getRectanglePolygon(circleCenter, rectangleSideA, rectangleSideB, rectangleRotation*-1);
const rectangleToTurfPoly = toTurfPolygon(rectanglePoly);
const frontlinePolygonA = getFrontline(frontlineDataA);
let frontlinePolygonMergedA = mergeTurfPolygons(frontlinePolygonA.body,frontlinePolygonA.protrusions[0]);
for (let i = 1; i < frontlinePolygonA.protrusions.length; i++)
{
frontlinePolygonMergedA = addTurfPolygonToMerge(frontlinePolygonMergedA, frontlinePolygonA.protrusions[i]);
}
const frontlinePolygonB = getFrontline(frontlineDataB);
let frontlinePolygonMergedB = mergeTurfPolygons(frontlinePolygonB.body,frontlinePolygonB.protrusions[0]);
for (let i = 1; i < frontlinePolygonB.protrusions.length; i++)
{
frontlinePolygonMergedB = addTurfPolygonToMerge(frontlinePolygonMergedB, frontlinePolygonB.protrusions[i]);
}
const frontlinePolygonC = getFrontline(frontlineDataC);
let frontlinePolygonMergedLeft = mergeTurfPolygons(frontlinePolygonC.bodyLeft, frontlinePolygonC.protrusionsLeft[0]);
for (let i = 1; i < frontlinePolygonC.protrusionsLeft.length; i++) {
frontlinePolygonMergedLeft = addTurfPolygonToMerge(frontlinePolygonMergedLeft, frontlinePolygonC.protrusionsLeft[i]);
}
let frontlinePolygonMergedRight = mergeTurfPolygons(frontlinePolygonC.bodyRight, frontlinePolygonC.protrusionsRight[0]);
for (let i = 1; i < frontlinePolygonC.protrusionsRight.length; i++) {
frontlinePolygonMergedRight = addTurfPolygonToMerge(frontlinePolygonMergedRight, frontlinePolygonC.protrusionsRight[i]);
}*/
//const circleGeoJSON = getCircleGeoJSON({x: 20, y: 80}, 2, 50, map);
const pointsB = [
{ x: 70, y: 38 },
{ x: 71, y: 45},
{ x: 65, y: 50 },
{ x: 70, y: 53}
];
const arrowDataB = {
points: pointsB,
splineStep: 0.01,
spacing: 0.01,
offsetDistance: 1
};
const styleB = {
calculation: ARROW_BODY_STYLE_LINEAR,
range: 1,
minValue: 0.1
};
const arrowHeadDataB = {
widthArrow: 1,
lengthArrow: 1
};
const arrowPolygonB = getArrowPolygon(arrowDataB, styleB, arrowHeadDataB);
const pointsC= [
{ x: 50, y: 38 },
{ x: 51, y: 45},
{ x: 45, y: 50 },
{ x: 48, y: 55}
];
const arrowDataC = {
points: pointsC,
splineStep: 0.02,
spacing: 1,
offsetDistance: 1
};
const styleC = {
calculation: ARROW_BODY_STYLE_LINEAR,
range: 1,
minValue: 0.1
};
const arrowHeadDataC = {
widthArrow: 1,
lengthArrow: 1
};
const arrowPolygonC = getArrowPolygon(arrowDataC, styleC, arrowHeadDataC);
const points = [
{ x: 80, y: 20 },
{ x: 81, y: 22},
{ x: 82, y: 28 },
{ x: 81, y: 30},
{ x: 80, y: 20}
];
// Turf polygon
const turfPolygon = turf.polygon([[
[20, 80],
[22, 81],
[28, 82],
[30, 81],
[20, 80]
]]);
const pointsA= [
{ x: 80, y: 38 },
{ x: 81, y: 45},
{ x: 75, y: 50 },
{ x: 78, y: 55}
];
const arrowDataA = {
points: pointsA,
splineStep: 0.2,
spacing: 3,
offsetDistance: 1
};
const styleA = {
calculation: ARROW_BODY_STYLE_LINEAR,
range: 1,
minValue: 0.1
};
const arrowHeadDataA = {
widthArrow: 1,
lengthArrow: 1
};
const arrowPolygonA = getArrowPolygon(arrowDataA, styleA, arrowHeadDataA);
const latLonGrid = generateLatLonGrid(5);
function createIsoscelesTriangle(center, baseLengthMeters, heightMeters, bearing = 0) {
const halfBase = baseLengthMeters / 2;
// Výpočet bodů základny (levý a pravý bod)
const leftBase = turf.destination(center, halfBase, bearing - 90, { units: 'meters' });
const rightBase = turf.destination(center, halfBase, bearing + 90, { units: 'meters' });
// Výpočet vrcholu trojúhelníku směr daný bearing (nahoru např. 0°)
const apex = turf.destination(center, heightMeters, bearing, { units: 'meters' });
const triangle = turf.polygon([[
leftBase.geometry.coordinates,
rightBase.geometry.coordinates,
apex.geometry.coordinates,
leftBase.geometry.coordinates // Uzavření polygonu
]]);
return triangle;
}
function cubicInterpolate(p, x) {
return p[1] + 0.5 * x * (p[2] - p[0] + x * (2.0 * p[0] - 5.0 * p[1] + 4.0 * p[2] - p[3] + x * (3.0 * (p[1] - p[2]) + p[3] - p[0])));
}
function interpolatePointsCatmullRom(points, segments = 10) {
if (points.length < 2) return points;
const extended = [points[0], ...points, points[points.length - 1]];
const interpolated = [];
for (let i = 1; i < extended.length - 2; i++) {
for (let j = 0; j < segments; j++) {
const t = j / segments;
const lon = cubicInterpolate([extended[i - 1][0], extended[i][0], extended[i + 1][0], extended[i + 2][0]], t);
const lat = cubicInterpolate([extended[i - 1][1], extended[i][1], extended[i + 1][1], extended[i + 2][1]], t);
interpolated.push([lon, lat]);
}
}
interpolated.push(points[points.length - 1]);
return interpolated;
}
function computeSideOffsets(points, offsetMeters) {
const left = [];
const right = [];
for (let i = 1; i < points.length; i++) {
const prev = points[i - 1];
const curr = points[i];
const bearing = turf.bearing(turf.point(prev), turf.point(curr));
const leftOffset = turf.destination(turf.point(curr), offsetMeters, bearing - 90, { units: 'meters' });
const rightOffset = turf.destination(turf.point(curr), offsetMeters, bearing + 90, { units: 'meters' });
left.push(leftOffset.geometry.coordinates);
right.push(rightOffset.geometry.coordinates);
}
return { left, right };
}
function createIsoscelesTriangleCoords(center, baseLengthMeters, heightMeters, bearing) {
const halfBase = baseLengthMeters / 2;
const left = turf.destination(center, halfBase, bearing - 90, { units: 'meters' }).geometry.coordinates;
const right = turf.destination(center, halfBase, bearing + 90, { units: 'meters' }).geometry.coordinates;
const tip = turf.destination(center, heightMeters, bearing, { units: 'meters' }).geometry.coordinates;
console.log("Aktuální bod:", left);
console.log("Aktuální bod:", right);
console.log("Aktuální bod:", tip);
return [left, right, tip];
}
function drawArrowPolygon(map, basePoints, offset = 10000) {
const smooth = interpolatePointsCatmullRom(basePoints, 20);
const { leftSidePoints, rightSidePoints } = computeSidesWGS84(smooth, offset);
console.log("Aktuální bod:", tip);
const end = smooth[smooth.length - 1];
const prev = smooth[smooth.length - 2];
const bearing = turf.bearing(turf.point(prev), turf.point(end));
const triangleCoords = createIsoscelesTriangleCoords(turf.point(end), offset * 2, offset * 3, bearing);
const polygonCoords = [
...leftSidePoints,
...triangleCoords,
...rightSidePoints.reverse(),
leftSidePoints[0]
];
const fullPolygon = turf.polygon([[...polygonCoords]]);
map.addSource("arrow-shape", {
type: "geojson",
data: fullPolygon
});
map.addLayer({
id: "arrow-shape",
type: "fill",
source: "arrow-shape",
paint: {
"fill-color": "#ff0000",
"fill-opacity": 0.7
}
});
}
function computeSidesWGS84(points, offsetDistanceMeters = 1000) {
const leftSidePoints = [];
const rightSidePoints = [];
for (let i = 1; i < points.length; i++) {
const prev = points[i - 1];
const curr = points[i];
const bearing = turf.bearing(turf.point(prev), turf.point(curr));
const leftBearing = bearing - 90;
const rightBearing = bearing + 90;
const leftPoint = turf.destination(turf.point(curr), offsetDistanceMeters, leftBearing, { units: 'meters' });
const rightPoint = turf.destination(turf.point(curr), offsetDistanceMeters, rightBearing, { units: 'meters' });
leftSidePoints.push(leftPoint.geometry.coordinates);
rightSidePoints.push(rightPoint.geometry.coordinates);
}
// První bod
const first = points[0];
const second = points[1];
const initialBearing = turf.bearing(turf.point(first), turf.point(second));
const leftInitial = turf.destination(turf.point(first), offsetDistanceMeters, initialBearing - 90, { units: 'meters' });
const rightInitial = turf.destination(turf.point(first), offsetDistanceMeters, initialBearing + 90, { units: 'meters' });
leftSidePoints.unshift(leftInitial.geometry.coordinates);
rightSidePoints.unshift(rightInitial.geometry.coordinates);
console.log("Aktuální bod:", leftSidePoints);
console.log("Aktuální bod:", rightSidePoints);
return {
leftSidePoints,
rightSidePoints
};
}
function drawSideLines(map, sides, prefix = "arrow-side") {
map.addSource(`${prefix}-left`, {
type: "geojson",
data: turf.lineString(sides.leftSidePoints)
});
map.addLayer({
id: `${prefix}-left`,
type: "line",
source: `${prefix}-left`,
paint: {
"line-color": "blue",
"line-width": 2
}
});
map.addSource(`${prefix}-right`, {
type: "geojson",
data: turf.lineString(sides.rightSidePoints)
});
map.addLayer({
id: `${prefix}-right`,
type: "line",
source: `${prefix}-right`,
paint: {
"line-color": "green",
"line-width": 2
}
});
}
function drawSmoothLineThroughPoints(map, points, lineId = "smooth-line") {
const smoothPoints = interpolatePointsCatmullRom(points, 20);
const line = turf.lineString(smoothPoints);
map.addSource(lineId, {
type: "geojson",
data: line
});
map.addLayer({
id: lineId,
type: "line",
source: lineId,
paint: {
"line-color": "red",
"line-width": 3
}
});
// Boční linie
const sides = computeSidesWGS84(smoothPoints, 10000); // 10 km offset
drawSideLines(map, sides, lineId + "-sides");
// Šipka na konci
const lastPoint = smoothPoints[smoothPoints.length - 1];
const secondLastPoint = smoothPoints[smoothPoints.length - 2];
const bearing = turf.bearing(turf.point(secondLastPoint), turf.point(lastPoint));
const triangle = createIsoscelesTriangle(turf.point(lastPoint), 60000, 80000, bearing); // 20km základna, 30km výška
map.addSource(lineId + "-arrow", {
type: "geojson",
data: triangle
});
map.addLayer({
id: lineId + "-arrow",
type: "fill",
source: lineId + "-arrow",
paint: {
"fill-color": "#ff0000",
"fill-opacity": 0.7
}
});
}
map.on('load', () => {
const points = [
[14.42076, 50.08804], // Praha
[15.0, 50.0],
[16.3725, 48.2082], // Vídeň
[17.0, 49.0],
[13.4050, 52.52] // Berlín
];
function createIsoscelesTriangle(center, baseLengthMeters, heightMeters, bearing = 0) {
const halfBase = baseLengthMeters / 2;
const leftBase = turf.destination(center, halfBase, bearing - 90, { units: 'meters' });
const rightBase = turf.destination(center, halfBase, bearing + 90, { units: 'meters' });
const apex = turf.destination(center, heightMeters, bearing, { units: 'meters' });
return turf.polygon([[
leftBase.geometry.coordinates,
rightBase.geometry.coordinates,
apex.geometry.coordinates,
leftBase.geometry.coordinates
]]);
}
const center = turf.point([52.95, 69.95]); // výchozí střed základny
// Vytvoř polygon trojúhelníku
const triangle = createIsoscelesTriangle(center, 40000, 100000, 10); // 2 km základna, 1 km výška, směr 0° (na sever)
map.addSource("triangle", {
type: "geojson",
data: triangle
});
map.addLayer({
id: "triangle",
type: "fill",
source: "triangle",
paint: {
"fill-color": "purple",
"fill-opacity": 0.5
}
});
map.addLayer({
id: "triangle-outline",
type: "line",
source: "triangle",
paint: {
"line-color": "#000",
"line-width": 2
}
});
map.addSource("latLonGrid", {
type: "geojson",
data: latLonGrid
});
map.addLayer({
id: "latLonGrid",
type: "line",
source: "latLonGrid",
layout: {},
paint: {
"line-color": "#888",
"line-width": 1,
"line-opacity": 0.5
}
});
// Generuj GeoJSON pro kruh
const circleGeoJSON = getCirclePolygon([20, 80], 120, 20);
const circle = turf.circle([20, 80], 120000, { units: "meters", steps: 64 });
const rectangleGeoJSON = getRectanglePolygon([20, 80], 2200, 2200);
const fsdafds = toTurfPolygon(points);
const arrowBGeoJSON = toTurfPolygon(arrowPolygonB);
const arrowCGeoJSON = toTurfPolygon(arrowPolygonC);
const arrowAGeoJSON = toTurfPolygon(arrowPolygonA);
//console.log(JSON.stringify(arrowAGeoJSON, null, 2));
// Arrow
// Přidání GeoJSON jako zdroj
map.addSource("arrowPolygonA", {
type: "geojson",
data: arrowAGeoJSON
});
// Vrstva pro výplň polygonu
map.addLayer({
id: "arrowPolygonA",
type: "fill",
source: "arrowPolygonA",
layout: {},
paint: {
"fill-color": "pink",
"fill-opacity": 0.6
}
});
// Vrstva pro obrys polygonu
map.addLayer({
id: "arrowPolygonA-outline",
type: "line",
source: "arrowPolygonA",
paint: {
"line-color": "#000",
"line-width": 3
}
});
// Arrow
// Přidání GeoJSON jako zdroj
map.addSource("arrowPolygonB", {
type: "geojson",
data: arrowBGeoJSON
});
// Vrstva pro výplň polygonu
map.addLayer({
id: "arrowPolygonB",
type: "fill",
source: "arrowPolygonB",
layout: {},
paint: {
"fill-color": "yellow",
"fill-opacity": 0.6
}
});
// Vrstva pro obrys polygonu
map.addLayer({
id: "arrowPolygonB-outline",
type: "line",
source: "arrowPolygonB",
paint: {
"line-color": "#000",
"line-width": 3
}
});
// Arrow
// Přidání GeoJSON jako zdroj
map.addSource("arrowPolygonC", {
type: "geojson",
data: arrowCGeoJSON
});
// Vrstva pro výplň polygonu
map.addLayer({
id: "arrowPolygonC",
type: "fill",
source: "arrowPolygonC",
layout: {},
paint: {
"fill-color": "yellow",
"fill-opacity": 0.6
}
});
// Vrstva pro obrys polygonu
map.addLayer({
id: "arrowPolygonC-outline",
type: "line",
source: "arrowPolygonC",
paint: {
"line-color": "#000",
"line-width": 3
}
});
// CIRCLE
// Přidání GeoJSON jako zdroj
map.addSource("circlePolygon", {
"type": "geojson",
"data": circleGeoJSON
});
// Přidání vrstvy pro vykreslení polygonu
map.addLayer({
"id": "circlePolygon",
"type": "fill",
"source": "circlePolygon",
"layout": {},
"paint": {
"fill-color": "blue",
"fill-opacity": 0.6
}
});
// Přidání outline pro polygon
map.addLayer({
"id": "circlePolygon-outline",
"type": "line",
"source": "circlePolygon",
"paint": {
"line-color": "#000",
"line-width": 3
}
});
// RECTANGLE
map.addSource("rectanglePolygon", {
"type": "geojson",
"data": rectangleGeoJSON
});
// Přidání vrstvy pro vykreslení polygonu
map.addLayer({
"id": "rectanglePolygon",
"type": "fill",
"source": "rectanglePolygon",
"layout": {},
"paint": {
"fill-color": "red",
"fill-opacity": 0.6
}
});
// Přidání outline pro polygon
map.addLayer({
"id": "rectanglePolygon-outline",
"type": "line",
"source": "rectanglePolygon",
"paint": {
"line-color": "#000",
"line-width": 3
}
});
});
function generateLatLonGrid(step = 10) {
const features = [];
// Rovnoběžky (latitudes)
for (let lat = -80; lat <= 80; lat += step) {
features.push({
type: "Feature",
geometry: {
type: "LineString",
coordinates: Array.from({ length: 37 }, (_, i) => [-180 + i * 10, lat])
},
properties: {
type: "latitude",
value: lat
}
});
}
// Poledníky (longitudes)
for (let lon = -180; lon <= 180; lon += step) {
features.push({
type: "Feature",
geometry: {
type: "LineString",
coordinates: Array.from({ length: 17 }, (_, i) => [lon, -80 + i * 10])
},
properties: {
type: "longitude",
value: lon
}
});
}
return {
type: "FeatureCollection",
features
};
}