Mercurial > gemma
view client/src/application/lib/geo.js @ 677:3605af94d1ee
fix: prepare profile calculation algorithm fixed
The x-value of a point is determined according to its reference point
* in case of the first segment, it is the first element of the line string
* in case of consecutive segments it is the last point of the previous segment
author | Thomas Junk <thomas.junk@intevation.de> |
---|---|
date | Wed, 19 Sep 2018 16:37:03 +0200 |
parents | 4c36b0e39d78 |
children | 87ea9d267c2b |
line wrap: on
line source
/** * * Distance calculations * JS transposition of cross.go functions * */ const EARTHRADIUS = 6378137.0; /** * Converts to radiant * @param {degree} d */ const deg2rad = d => { return (d * Math.PI) / 180.0; }; /** * Calculates the difference between two points in m * * Points are given with {lat: $lat, lon: $lon} * * @param {object} P1 * @param {object} P2 */ const distanceBetween = (P1, P2) => { const dLat = deg2rad(P2.lat - P1.lat); let dLng = Math.abs(deg2rad(P2.lon - P1.lon)); if (dLng > Math.PI) { dLng = 2 * Math.PI - dLng; } const x = dLng * Math.cos(deg2rad((P1.lat + P2.lat) / 2.0)); return Math.sqrt(dLat * dLat + x * x) * EARTHRADIUS; }; /** * Takes a triple of [lat, long, alt] and generates * an object with according attributes * { * lat: $lat, * lon: $lon, * alt: $alt * } * * @param {array} coords */ const generatePoint = coords => { return { lon: coords[0], lat: coords[1], alt: coords[2] }; }; /** * Has geoJSON as its input and transforms * given coordinates * * a) extracting the minimum altitude * b) extracting the maximum altitude * c) calculating the total length of the given profile * d) transposes the datapoints given to the first point of the first section * * The calculation of total equals the sum of partial distances between points * The x-value of a point is determined according to its reference point * in case of the first segment, it is the first element of the line string * in case of consecutive segments it is the last point of the previous segment * * @param {object} feature */ const transform = feature => { const sections = feature.geometry.coordinates; let firstPoint = generatePoint(sections[0][0]); let coordinates = []; let totalLength = 0; let minAlt = firstPoint.alt; let maxAlt = firstPoint.alt; for (let section of sections) { let sectionCoordinates = []; let previousPoint = generatePoint(section[0]); let currentPoint = null; for (let coords of section) { currentPoint = generatePoint(coords); let x = distanceBetween(firstPoint, currentPoint); let y = coords[2]; sectionCoordinates.push({ x: x, y: y }); totalLength += distanceBetween(currentPoint, previousPoint); previousPoint = currentPoint; if (y < minAlt) minAlt = y; if (y > maxAlt) maxAlt = y; } coordinates.push(sectionCoordinates); firstPoint = currentPoint; } return { coordinates, totalLength, minAlt, maxAlt }; }; /** * Prepare profile takes geoJSON data in form of * a MultiLineString, e.g. * * { * type: "Feature", * geometry: { * type: "MultiLineString", * coordinates: [ * [ * [16.53593398, 48.14694085, -146.52392755] * ... * ]] * * and transforms it to a structure representing the number of sections * where data is present with according lengths and the points * * { * { points: * [ * [ { x: 0.005798201616417183, y: -146.52419461 }, * { x: 0, y: -146.52394016 } * ... * ] * ] * totalLength: 160.06814078495722, * minAlt: -146.73122231, * maxAlt: -145.65155866 * } * * @param {object} geoJSON */ const prepareProfile = geoJSON => { const { coordinates, totalLength, minAlt, maxAlt } = transform(geoJSON); return { points: coordinates, totalLength: totalLength, minAlt: minAlt, maxAlt: maxAlt }; }; export { prepareProfile };