@allmaps/transform
Advanced tools
Comparing version 1.0.0-alpha.3 to 1.0.0-alpha.4
@@ -591,5 +591,443 @@ 'use strict'; | ||
/** | ||
* @module helpers | ||
*/ | ||
/** | ||
* Earth Radius used with the Harvesine formula and approximates using a spherical (non-ellipsoid) Earth. | ||
* | ||
* @memberof helpers | ||
* @type {number} | ||
*/ | ||
var earthRadius = 6371008.8; | ||
/** | ||
* Unit of measurement factors using a spherical (non-ellipsoid) earth radius. | ||
* | ||
* @memberof helpers | ||
* @type {Object} | ||
*/ | ||
var factors = { | ||
centimeters: earthRadius * 100, | ||
centimetres: earthRadius * 100, | ||
degrees: earthRadius / 111325, | ||
feet: earthRadius * 3.28084, | ||
inches: earthRadius * 39.37, | ||
kilometers: earthRadius / 1000, | ||
kilometres: earthRadius / 1000, | ||
meters: earthRadius, | ||
metres: earthRadius, | ||
miles: earthRadius / 1609.344, | ||
millimeters: earthRadius * 1000, | ||
millimetres: earthRadius * 1000, | ||
nauticalmiles: earthRadius / 1852, | ||
radians: 1, | ||
yards: earthRadius / 1.0936, | ||
}; | ||
/** | ||
* Wraps a GeoJSON {@link Geometry} in a GeoJSON {@link Feature}. | ||
* | ||
* @name feature | ||
* @param {Geometry} geometry input geometry | ||
* @param {Object} [properties={}] an Object of key-value pairs to add as properties | ||
* @param {Object} [options={}] Optional Parameters | ||
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature | ||
* @param {string|number} [options.id] Identifier associated with the Feature | ||
* @returns {Feature} a GeoJSON Feature | ||
* @example | ||
* var geometry = { | ||
* "type": "Point", | ||
* "coordinates": [110, 50] | ||
* }; | ||
* | ||
* var feature = turf.feature(geometry); | ||
* | ||
* //=feature | ||
*/ | ||
function feature(geom, properties, options) { | ||
if (options === void 0) { options = {}; } | ||
var feat = { type: "Feature" }; | ||
if (options.id === 0 || options.id) { | ||
feat.id = options.id; | ||
} | ||
if (options.bbox) { | ||
feat.bbox = options.bbox; | ||
} | ||
feat.properties = properties || {}; | ||
feat.geometry = geom; | ||
return feat; | ||
} | ||
/** | ||
* Creates a {@link Point} {@link Feature} from a Position. | ||
* | ||
* @name point | ||
* @param {Array<number>} coordinates longitude, latitude position (each in decimal degrees) | ||
* @param {Object} [properties={}] an Object of key-value pairs to add as properties | ||
* @param {Object} [options={}] Optional Parameters | ||
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature | ||
* @param {string|number} [options.id] Identifier associated with the Feature | ||
* @returns {Feature<Point>} a Point feature | ||
* @example | ||
* var point = turf.point([-75.343, 39.984]); | ||
* | ||
* //=point | ||
*/ | ||
function point$1(coordinates, properties, options) { | ||
if (options === void 0) { options = {}; } | ||
if (!coordinates) { | ||
throw new Error("coordinates is required"); | ||
} | ||
if (!Array.isArray(coordinates)) { | ||
throw new Error("coordinates must be an Array"); | ||
} | ||
if (coordinates.length < 2) { | ||
throw new Error("coordinates must be at least 2 numbers long"); | ||
} | ||
if (!isNumber(coordinates[0]) || !isNumber(coordinates[1])) { | ||
throw new Error("coordinates must contain numbers"); | ||
} | ||
var geom = { | ||
type: "Point", | ||
coordinates: coordinates, | ||
}; | ||
return feature(geom, properties, options); | ||
} | ||
/** | ||
* Convert a distance measurement (assuming a spherical Earth) from radians to a more friendly unit. | ||
* Valid units: miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet | ||
* | ||
* @name radiansToLength | ||
* @param {number} radians in radians across the sphere | ||
* @param {string} [units="kilometers"] can be degrees, radians, miles, inches, yards, metres, | ||
* meters, kilometres, kilometers. | ||
* @returns {number} distance | ||
*/ | ||
function radiansToLength(radians, units) { | ||
if (units === void 0) { units = "kilometers"; } | ||
var factor = factors[units]; | ||
if (!factor) { | ||
throw new Error(units + " units is invalid"); | ||
} | ||
return radians * factor; | ||
} | ||
/** | ||
* Convert a distance measurement (assuming a spherical Earth) from a real-world unit into radians | ||
* Valid units: miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet | ||
* | ||
* @name lengthToRadians | ||
* @param {number} distance in real units | ||
* @param {string} [units="kilometers"] can be degrees, radians, miles, inches, yards, metres, | ||
* meters, kilometres, kilometers. | ||
* @returns {number} radians | ||
*/ | ||
function lengthToRadians(distance, units) { | ||
if (units === void 0) { units = "kilometers"; } | ||
var factor = factors[units]; | ||
if (!factor) { | ||
throw new Error(units + " units is invalid"); | ||
} | ||
return distance / factor; | ||
} | ||
/** | ||
* Converts an angle in radians to degrees | ||
* | ||
* @name radiansToDegrees | ||
* @param {number} radians angle in radians | ||
* @returns {number} degrees between 0 and 360 degrees | ||
*/ | ||
function radiansToDegrees(radians) { | ||
var degrees = radians % (2 * Math.PI); | ||
return (degrees * 180) / Math.PI; | ||
} | ||
/** | ||
* Converts an angle in degrees to radians | ||
* | ||
* @name degreesToRadians | ||
* @param {number} degrees angle between 0 and 360 degrees | ||
* @returns {number} angle in radians | ||
*/ | ||
function degreesToRadians(degrees) { | ||
var radians = degrees % 360; | ||
return (radians * Math.PI) / 180; | ||
} | ||
/** | ||
* isNumber | ||
* | ||
* @param {*} num Number to validate | ||
* @returns {boolean} true/false | ||
* @example | ||
* turf.isNumber(123) | ||
* //=true | ||
* turf.isNumber('foo') | ||
* //=false | ||
*/ | ||
function isNumber(num) { | ||
return !isNaN(num) && num !== null && !Array.isArray(num); | ||
} | ||
/** | ||
* Unwrap a coordinate from a Point Feature, Geometry or a single coordinate. | ||
* | ||
* @name getCoord | ||
* @param {Array<number>|Geometry<Point>|Feature<Point>} coord GeoJSON Point or an Array of numbers | ||
* @returns {Array<number>} coordinates | ||
* @example | ||
* var pt = turf.point([10, 10]); | ||
* | ||
* var coord = turf.getCoord(pt); | ||
* //= [10, 10] | ||
*/ | ||
function getCoord(coord) { | ||
if (!coord) { | ||
throw new Error("coord is required"); | ||
} | ||
if (!Array.isArray(coord)) { | ||
if (coord.type === "Feature" && | ||
coord.geometry !== null && | ||
coord.geometry.type === "Point") { | ||
return coord.geometry.coordinates; | ||
} | ||
if (coord.type === "Point") { | ||
return coord.coordinates; | ||
} | ||
} | ||
if (Array.isArray(coord) && | ||
coord.length >= 2 && | ||
!Array.isArray(coord[0]) && | ||
!Array.isArray(coord[1])) { | ||
return coord; | ||
} | ||
throw new Error("coord must be GeoJSON Point or an Array of numbers"); | ||
} | ||
// http://en.wikipedia.org/wiki/Haversine_formula | ||
// http://www.movable-type.co.uk/scripts/latlong.html | ||
/** | ||
* Takes two {@link Point|points} and finds the geographic bearing between them, | ||
* i.e. the angle measured in degrees from the north line (0 degrees) | ||
* | ||
* @name bearing | ||
* @param {Coord} start starting Point | ||
* @param {Coord} end ending Point | ||
* @param {Object} [options={}] Optional parameters | ||
* @param {boolean} [options.final=false] calculates the final bearing if true | ||
* @returns {number} bearing in decimal degrees, between -180 and 180 degrees (positive clockwise) | ||
* @example | ||
* var point1 = turf.point([-75.343, 39.984]); | ||
* var point2 = turf.point([-75.534, 39.123]); | ||
* | ||
* var bearing = turf.bearing(point1, point2); | ||
* | ||
* //addToMap | ||
* var addToMap = [point1, point2] | ||
* point1.properties['marker-color'] = '#f00' | ||
* point2.properties['marker-color'] = '#0f0' | ||
* point1.properties.bearing = bearing | ||
*/ | ||
function bearing(start, end, options) { | ||
if (options === void 0) { options = {}; } | ||
// Reverse calculation | ||
if (options.final === true) { | ||
return calculateFinalBearing(start, end); | ||
} | ||
var coordinates1 = getCoord(start); | ||
var coordinates2 = getCoord(end); | ||
var lon1 = degreesToRadians(coordinates1[0]); | ||
var lon2 = degreesToRadians(coordinates2[0]); | ||
var lat1 = degreesToRadians(coordinates1[1]); | ||
var lat2 = degreesToRadians(coordinates2[1]); | ||
var a = Math.sin(lon2 - lon1) * Math.cos(lat2); | ||
var b = Math.cos(lat1) * Math.sin(lat2) - | ||
Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1); | ||
return radiansToDegrees(Math.atan2(a, b)); | ||
} | ||
/** | ||
* Calculates Final Bearing | ||
* | ||
* @private | ||
* @param {Coord} start starting Point | ||
* @param {Coord} end ending Point | ||
* @returns {number} bearing | ||
*/ | ||
function calculateFinalBearing(start, end) { | ||
// Swap start & end | ||
var bear = bearing(end, start); | ||
bear = (bear + 180) % 360; | ||
return bear; | ||
} | ||
// http://en.wikipedia.org/wiki/Haversine_formula | ||
/** | ||
* Takes a {@link Point} and calculates the location of a destination point given a distance in | ||
* degrees, radians, miles, or kilometers; and bearing in degrees. | ||
* This uses the [Haversine formula](http://en.wikipedia.org/wiki/Haversine_formula) to account for global curvature. | ||
* | ||
* @name destination | ||
* @param {Coord} origin starting point | ||
* @param {number} distance distance from the origin point | ||
* @param {number} bearing ranging from -180 to 180 | ||
* @param {Object} [options={}] Optional parameters | ||
* @param {string} [options.units='kilometers'] miles, kilometers, degrees, or radians | ||
* @param {Object} [options.properties={}] Translate properties to Point | ||
* @returns {Feature<Point>} destination point | ||
* @example | ||
* var point = turf.point([-75.343, 39.984]); | ||
* var distance = 50; | ||
* var bearing = 90; | ||
* var options = {units: 'miles'}; | ||
* | ||
* var destination = turf.destination(point, distance, bearing, options); | ||
* | ||
* //addToMap | ||
* var addToMap = [point, destination] | ||
* destination.properties['marker-color'] = '#f00'; | ||
* point.properties['marker-color'] = '#0f0'; | ||
*/ | ||
function destination(origin, distance, bearing, options) { | ||
if (options === void 0) { options = {}; } | ||
// Handle input | ||
var coordinates1 = getCoord(origin); | ||
var longitude1 = degreesToRadians(coordinates1[0]); | ||
var latitude1 = degreesToRadians(coordinates1[1]); | ||
var bearingRad = degreesToRadians(bearing); | ||
var radians = lengthToRadians(distance, options.units); | ||
// Main | ||
var latitude2 = Math.asin(Math.sin(latitude1) * Math.cos(radians) + | ||
Math.cos(latitude1) * Math.sin(radians) * Math.cos(bearingRad)); | ||
var longitude2 = longitude1 + | ||
Math.atan2(Math.sin(bearingRad) * Math.sin(radians) * Math.cos(latitude1), Math.cos(radians) - Math.sin(latitude1) * Math.sin(latitude2)); | ||
var lng = radiansToDegrees(longitude2); | ||
var lat = radiansToDegrees(latitude2); | ||
return point$1([lng, lat], options.properties); | ||
} | ||
//http://en.wikipedia.org/wiki/Haversine_formula | ||
//http://www.movable-type.co.uk/scripts/latlong.html | ||
/** | ||
* Calculates the distance between two {@link Point|points} in degrees, radians, miles, or kilometers. | ||
* This uses the [Haversine formula](http://en.wikipedia.org/wiki/Haversine_formula) to account for global curvature. | ||
* | ||
* @name distance | ||
* @param {Coord} from origin point | ||
* @param {Coord} to destination point | ||
* @param {Object} [options={}] Optional parameters | ||
* @param {string} [options.units='kilometers'] can be degrees, radians, miles, or kilometers | ||
* @returns {number} distance between the two points | ||
* @example | ||
* var from = turf.point([-75.343, 39.984]); | ||
* var to = turf.point([-75.534, 39.123]); | ||
* var options = {units: 'miles'}; | ||
* | ||
* var distance = turf.distance(from, to, options); | ||
* | ||
* //addToMap | ||
* var addToMap = [from, to]; | ||
* from.properties.distance = distance; | ||
* to.properties.distance = distance; | ||
*/ | ||
function distance(from, to, options) { | ||
if (options === void 0) { options = {}; } | ||
var coordinates1 = getCoord(from); | ||
var coordinates2 = getCoord(to); | ||
var dLat = degreesToRadians(coordinates2[1] - coordinates1[1]); | ||
var dLon = degreesToRadians(coordinates2[0] - coordinates1[0]); | ||
var lat1 = degreesToRadians(coordinates1[1]); | ||
var lat2 = degreesToRadians(coordinates2[1]); | ||
var a = Math.pow(Math.sin(dLat / 2), 2) + | ||
Math.pow(Math.sin(dLon / 2), 2) * Math.cos(lat1) * Math.cos(lat2); | ||
return radiansToLength(2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)), options.units); | ||
} | ||
/** | ||
* Takes two {@link Point|points} and returns a point midway between them. | ||
* The midpoint is calculated geodesically, meaning the curvature of the earth is taken into account. | ||
* | ||
* @name midpoint | ||
* @param {Coord} point1 first point | ||
* @param {Coord} point2 second point | ||
* @returns {Feature<Point>} a point midway between `pt1` and `pt2` | ||
* @example | ||
* var point1 = turf.point([144.834823, -37.771257]); | ||
* var point2 = turf.point([145.14244, -37.830937]); | ||
* | ||
* var midpoint = turf.midpoint(point1, point2); | ||
* | ||
* //addToMap | ||
* var addToMap = [point1, point2, midpoint]; | ||
* midpoint.properties['marker-color'] = '#f00'; | ||
*/ | ||
function midpoint(point1, point2) { | ||
var dist = distance(point1, point2); | ||
var heading = bearing(point1, point2); | ||
var midpoint = destination(point1, dist / 2, heading); | ||
return midpoint; | ||
} | ||
function point (point) { | ||
return { | ||
type: 'Point', | ||
coordinates: point | ||
} | ||
} | ||
function polygonToWorld (transformArgs, points, maxOffsetPercentage = 0.01, maxDepth = 8) { | ||
const worldPoints = points | ||
.map((point) => ({ | ||
image: point, | ||
world: toWorld(transformArgs, point) | ||
})); | ||
// if (maxOffsetPercentage > 0) | ||
const segments = Array.from(Array(worldPoints.length - 1)) | ||
.map((_, index) => ({ | ||
from: worldPoints[index], | ||
to: worldPoints[index + 1] | ||
})); | ||
const segmentsWithMidpoints = segments | ||
.map((segment) => addMidpoints(transformArgs, segment, maxOffsetPercentage, maxDepth)) | ||
.flat(Infinity); | ||
return { | ||
type: 'Polygon', | ||
coordinates: [ | ||
[ | ||
segmentsWithMidpoints[0].from.world, | ||
...segmentsWithMidpoints.map((segment) => segment.to.world) | ||
] | ||
] | ||
} | ||
} | ||
function addMidpoints (transformArgs, segment, maxOffsetPercentage, maxDepth, depth = 0) { | ||
const imageMidpoint = [ | ||
(segment.from.image[0] + segment.to.image[0]) / 2, | ||
(segment.from.image[1] + segment.to.image[1]) / 2 | ||
]; | ||
const segmentWorldMidpoint = midpoint(point(segment.from.world), point(segment.to.world)); | ||
const actualWorldMidpoint = point(toWorld(transformArgs, imageMidpoint)); | ||
const distanceSegment = distance(point(segment.from.world), point(segment.to.world)); | ||
const distanceMidpoints = distance(segmentWorldMidpoint, actualWorldMidpoint); | ||
if (distanceMidpoints / distanceSegment > maxOffsetPercentage && depth < maxDepth) { | ||
const newSegmentMidpoint = { | ||
image: imageMidpoint, | ||
world: actualWorldMidpoint.coordinates | ||
}; | ||
return [ | ||
addMidpoints(transformArgs, { from: segment.from, to: newSegmentMidpoint }, maxOffsetPercentage, depth + 1), | ||
addMidpoints(transformArgs, { from: newSegmentMidpoint, to: segment.to }, maxOffsetPercentage, depth + 1) | ||
] | ||
} else { | ||
return segment | ||
} | ||
} | ||
exports.createTransformer = createTransformer; | ||
exports.polygonToWorld = polygonToWorld; | ||
exports.toImage = toImage; | ||
exports.toWorld = toWorld; | ||
//# sourceMappingURL=index.js.map |
@@ -587,3 +587,440 @@ const HUGE_VAL = Number.POSITIVE_INFINITY; | ||
export { createTransformer, toImage, toWorld }; | ||
/** | ||
* @module helpers | ||
*/ | ||
/** | ||
* Earth Radius used with the Harvesine formula and approximates using a spherical (non-ellipsoid) Earth. | ||
* | ||
* @memberof helpers | ||
* @type {number} | ||
*/ | ||
var earthRadius = 6371008.8; | ||
/** | ||
* Unit of measurement factors using a spherical (non-ellipsoid) earth radius. | ||
* | ||
* @memberof helpers | ||
* @type {Object} | ||
*/ | ||
var factors = { | ||
centimeters: earthRadius * 100, | ||
centimetres: earthRadius * 100, | ||
degrees: earthRadius / 111325, | ||
feet: earthRadius * 3.28084, | ||
inches: earthRadius * 39.37, | ||
kilometers: earthRadius / 1000, | ||
kilometres: earthRadius / 1000, | ||
meters: earthRadius, | ||
metres: earthRadius, | ||
miles: earthRadius / 1609.344, | ||
millimeters: earthRadius * 1000, | ||
millimetres: earthRadius * 1000, | ||
nauticalmiles: earthRadius / 1852, | ||
radians: 1, | ||
yards: earthRadius / 1.0936, | ||
}; | ||
/** | ||
* Wraps a GeoJSON {@link Geometry} in a GeoJSON {@link Feature}. | ||
* | ||
* @name feature | ||
* @param {Geometry} geometry input geometry | ||
* @param {Object} [properties={}] an Object of key-value pairs to add as properties | ||
* @param {Object} [options={}] Optional Parameters | ||
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature | ||
* @param {string|number} [options.id] Identifier associated with the Feature | ||
* @returns {Feature} a GeoJSON Feature | ||
* @example | ||
* var geometry = { | ||
* "type": "Point", | ||
* "coordinates": [110, 50] | ||
* }; | ||
* | ||
* var feature = turf.feature(geometry); | ||
* | ||
* //=feature | ||
*/ | ||
function feature(geom, properties, options) { | ||
if (options === void 0) { options = {}; } | ||
var feat = { type: "Feature" }; | ||
if (options.id === 0 || options.id) { | ||
feat.id = options.id; | ||
} | ||
if (options.bbox) { | ||
feat.bbox = options.bbox; | ||
} | ||
feat.properties = properties || {}; | ||
feat.geometry = geom; | ||
return feat; | ||
} | ||
/** | ||
* Creates a {@link Point} {@link Feature} from a Position. | ||
* | ||
* @name point | ||
* @param {Array<number>} coordinates longitude, latitude position (each in decimal degrees) | ||
* @param {Object} [properties={}] an Object of key-value pairs to add as properties | ||
* @param {Object} [options={}] Optional Parameters | ||
* @param {Array<number>} [options.bbox] Bounding Box Array [west, south, east, north] associated with the Feature | ||
* @param {string|number} [options.id] Identifier associated with the Feature | ||
* @returns {Feature<Point>} a Point feature | ||
* @example | ||
* var point = turf.point([-75.343, 39.984]); | ||
* | ||
* //=point | ||
*/ | ||
function point$1(coordinates, properties, options) { | ||
if (options === void 0) { options = {}; } | ||
if (!coordinates) { | ||
throw new Error("coordinates is required"); | ||
} | ||
if (!Array.isArray(coordinates)) { | ||
throw new Error("coordinates must be an Array"); | ||
} | ||
if (coordinates.length < 2) { | ||
throw new Error("coordinates must be at least 2 numbers long"); | ||
} | ||
if (!isNumber(coordinates[0]) || !isNumber(coordinates[1])) { | ||
throw new Error("coordinates must contain numbers"); | ||
} | ||
var geom = { | ||
type: "Point", | ||
coordinates: coordinates, | ||
}; | ||
return feature(geom, properties, options); | ||
} | ||
/** | ||
* Convert a distance measurement (assuming a spherical Earth) from radians to a more friendly unit. | ||
* Valid units: miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet | ||
* | ||
* @name radiansToLength | ||
* @param {number} radians in radians across the sphere | ||
* @param {string} [units="kilometers"] can be degrees, radians, miles, inches, yards, metres, | ||
* meters, kilometres, kilometers. | ||
* @returns {number} distance | ||
*/ | ||
function radiansToLength(radians, units) { | ||
if (units === void 0) { units = "kilometers"; } | ||
var factor = factors[units]; | ||
if (!factor) { | ||
throw new Error(units + " units is invalid"); | ||
} | ||
return radians * factor; | ||
} | ||
/** | ||
* Convert a distance measurement (assuming a spherical Earth) from a real-world unit into radians | ||
* Valid units: miles, nauticalmiles, inches, yards, meters, metres, kilometers, centimeters, feet | ||
* | ||
* @name lengthToRadians | ||
* @param {number} distance in real units | ||
* @param {string} [units="kilometers"] can be degrees, radians, miles, inches, yards, metres, | ||
* meters, kilometres, kilometers. | ||
* @returns {number} radians | ||
*/ | ||
function lengthToRadians(distance, units) { | ||
if (units === void 0) { units = "kilometers"; } | ||
var factor = factors[units]; | ||
if (!factor) { | ||
throw new Error(units + " units is invalid"); | ||
} | ||
return distance / factor; | ||
} | ||
/** | ||
* Converts an angle in radians to degrees | ||
* | ||
* @name radiansToDegrees | ||
* @param {number} radians angle in radians | ||
* @returns {number} degrees between 0 and 360 degrees | ||
*/ | ||
function radiansToDegrees(radians) { | ||
var degrees = radians % (2 * Math.PI); | ||
return (degrees * 180) / Math.PI; | ||
} | ||
/** | ||
* Converts an angle in degrees to radians | ||
* | ||
* @name degreesToRadians | ||
* @param {number} degrees angle between 0 and 360 degrees | ||
* @returns {number} angle in radians | ||
*/ | ||
function degreesToRadians(degrees) { | ||
var radians = degrees % 360; | ||
return (radians * Math.PI) / 180; | ||
} | ||
/** | ||
* isNumber | ||
* | ||
* @param {*} num Number to validate | ||
* @returns {boolean} true/false | ||
* @example | ||
* turf.isNumber(123) | ||
* //=true | ||
* turf.isNumber('foo') | ||
* //=false | ||
*/ | ||
function isNumber(num) { | ||
return !isNaN(num) && num !== null && !Array.isArray(num); | ||
} | ||
/** | ||
* Unwrap a coordinate from a Point Feature, Geometry or a single coordinate. | ||
* | ||
* @name getCoord | ||
* @param {Array<number>|Geometry<Point>|Feature<Point>} coord GeoJSON Point or an Array of numbers | ||
* @returns {Array<number>} coordinates | ||
* @example | ||
* var pt = turf.point([10, 10]); | ||
* | ||
* var coord = turf.getCoord(pt); | ||
* //= [10, 10] | ||
*/ | ||
function getCoord(coord) { | ||
if (!coord) { | ||
throw new Error("coord is required"); | ||
} | ||
if (!Array.isArray(coord)) { | ||
if (coord.type === "Feature" && | ||
coord.geometry !== null && | ||
coord.geometry.type === "Point") { | ||
return coord.geometry.coordinates; | ||
} | ||
if (coord.type === "Point") { | ||
return coord.coordinates; | ||
} | ||
} | ||
if (Array.isArray(coord) && | ||
coord.length >= 2 && | ||
!Array.isArray(coord[0]) && | ||
!Array.isArray(coord[1])) { | ||
return coord; | ||
} | ||
throw new Error("coord must be GeoJSON Point or an Array of numbers"); | ||
} | ||
// http://en.wikipedia.org/wiki/Haversine_formula | ||
// http://www.movable-type.co.uk/scripts/latlong.html | ||
/** | ||
* Takes two {@link Point|points} and finds the geographic bearing between them, | ||
* i.e. the angle measured in degrees from the north line (0 degrees) | ||
* | ||
* @name bearing | ||
* @param {Coord} start starting Point | ||
* @param {Coord} end ending Point | ||
* @param {Object} [options={}] Optional parameters | ||
* @param {boolean} [options.final=false] calculates the final bearing if true | ||
* @returns {number} bearing in decimal degrees, between -180 and 180 degrees (positive clockwise) | ||
* @example | ||
* var point1 = turf.point([-75.343, 39.984]); | ||
* var point2 = turf.point([-75.534, 39.123]); | ||
* | ||
* var bearing = turf.bearing(point1, point2); | ||
* | ||
* //addToMap | ||
* var addToMap = [point1, point2] | ||
* point1.properties['marker-color'] = '#f00' | ||
* point2.properties['marker-color'] = '#0f0' | ||
* point1.properties.bearing = bearing | ||
*/ | ||
function bearing(start, end, options) { | ||
if (options === void 0) { options = {}; } | ||
// Reverse calculation | ||
if (options.final === true) { | ||
return calculateFinalBearing(start, end); | ||
} | ||
var coordinates1 = getCoord(start); | ||
var coordinates2 = getCoord(end); | ||
var lon1 = degreesToRadians(coordinates1[0]); | ||
var lon2 = degreesToRadians(coordinates2[0]); | ||
var lat1 = degreesToRadians(coordinates1[1]); | ||
var lat2 = degreesToRadians(coordinates2[1]); | ||
var a = Math.sin(lon2 - lon1) * Math.cos(lat2); | ||
var b = Math.cos(lat1) * Math.sin(lat2) - | ||
Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1); | ||
return radiansToDegrees(Math.atan2(a, b)); | ||
} | ||
/** | ||
* Calculates Final Bearing | ||
* | ||
* @private | ||
* @param {Coord} start starting Point | ||
* @param {Coord} end ending Point | ||
* @returns {number} bearing | ||
*/ | ||
function calculateFinalBearing(start, end) { | ||
// Swap start & end | ||
var bear = bearing(end, start); | ||
bear = (bear + 180) % 360; | ||
return bear; | ||
} | ||
// http://en.wikipedia.org/wiki/Haversine_formula | ||
/** | ||
* Takes a {@link Point} and calculates the location of a destination point given a distance in | ||
* degrees, radians, miles, or kilometers; and bearing in degrees. | ||
* This uses the [Haversine formula](http://en.wikipedia.org/wiki/Haversine_formula) to account for global curvature. | ||
* | ||
* @name destination | ||
* @param {Coord} origin starting point | ||
* @param {number} distance distance from the origin point | ||
* @param {number} bearing ranging from -180 to 180 | ||
* @param {Object} [options={}] Optional parameters | ||
* @param {string} [options.units='kilometers'] miles, kilometers, degrees, or radians | ||
* @param {Object} [options.properties={}] Translate properties to Point | ||
* @returns {Feature<Point>} destination point | ||
* @example | ||
* var point = turf.point([-75.343, 39.984]); | ||
* var distance = 50; | ||
* var bearing = 90; | ||
* var options = {units: 'miles'}; | ||
* | ||
* var destination = turf.destination(point, distance, bearing, options); | ||
* | ||
* //addToMap | ||
* var addToMap = [point, destination] | ||
* destination.properties['marker-color'] = '#f00'; | ||
* point.properties['marker-color'] = '#0f0'; | ||
*/ | ||
function destination(origin, distance, bearing, options) { | ||
if (options === void 0) { options = {}; } | ||
// Handle input | ||
var coordinates1 = getCoord(origin); | ||
var longitude1 = degreesToRadians(coordinates1[0]); | ||
var latitude1 = degreesToRadians(coordinates1[1]); | ||
var bearingRad = degreesToRadians(bearing); | ||
var radians = lengthToRadians(distance, options.units); | ||
// Main | ||
var latitude2 = Math.asin(Math.sin(latitude1) * Math.cos(radians) + | ||
Math.cos(latitude1) * Math.sin(radians) * Math.cos(bearingRad)); | ||
var longitude2 = longitude1 + | ||
Math.atan2(Math.sin(bearingRad) * Math.sin(radians) * Math.cos(latitude1), Math.cos(radians) - Math.sin(latitude1) * Math.sin(latitude2)); | ||
var lng = radiansToDegrees(longitude2); | ||
var lat = radiansToDegrees(latitude2); | ||
return point$1([lng, lat], options.properties); | ||
} | ||
//http://en.wikipedia.org/wiki/Haversine_formula | ||
//http://www.movable-type.co.uk/scripts/latlong.html | ||
/** | ||
* Calculates the distance between two {@link Point|points} in degrees, radians, miles, or kilometers. | ||
* This uses the [Haversine formula](http://en.wikipedia.org/wiki/Haversine_formula) to account for global curvature. | ||
* | ||
* @name distance | ||
* @param {Coord} from origin point | ||
* @param {Coord} to destination point | ||
* @param {Object} [options={}] Optional parameters | ||
* @param {string} [options.units='kilometers'] can be degrees, radians, miles, or kilometers | ||
* @returns {number} distance between the two points | ||
* @example | ||
* var from = turf.point([-75.343, 39.984]); | ||
* var to = turf.point([-75.534, 39.123]); | ||
* var options = {units: 'miles'}; | ||
* | ||
* var distance = turf.distance(from, to, options); | ||
* | ||
* //addToMap | ||
* var addToMap = [from, to]; | ||
* from.properties.distance = distance; | ||
* to.properties.distance = distance; | ||
*/ | ||
function distance(from, to, options) { | ||
if (options === void 0) { options = {}; } | ||
var coordinates1 = getCoord(from); | ||
var coordinates2 = getCoord(to); | ||
var dLat = degreesToRadians(coordinates2[1] - coordinates1[1]); | ||
var dLon = degreesToRadians(coordinates2[0] - coordinates1[0]); | ||
var lat1 = degreesToRadians(coordinates1[1]); | ||
var lat2 = degreesToRadians(coordinates2[1]); | ||
var a = Math.pow(Math.sin(dLat / 2), 2) + | ||
Math.pow(Math.sin(dLon / 2), 2) * Math.cos(lat1) * Math.cos(lat2); | ||
return radiansToLength(2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)), options.units); | ||
} | ||
/** | ||
* Takes two {@link Point|points} and returns a point midway between them. | ||
* The midpoint is calculated geodesically, meaning the curvature of the earth is taken into account. | ||
* | ||
* @name midpoint | ||
* @param {Coord} point1 first point | ||
* @param {Coord} point2 second point | ||
* @returns {Feature<Point>} a point midway between `pt1` and `pt2` | ||
* @example | ||
* var point1 = turf.point([144.834823, -37.771257]); | ||
* var point2 = turf.point([145.14244, -37.830937]); | ||
* | ||
* var midpoint = turf.midpoint(point1, point2); | ||
* | ||
* //addToMap | ||
* var addToMap = [point1, point2, midpoint]; | ||
* midpoint.properties['marker-color'] = '#f00'; | ||
*/ | ||
function midpoint(point1, point2) { | ||
var dist = distance(point1, point2); | ||
var heading = bearing(point1, point2); | ||
var midpoint = destination(point1, dist / 2, heading); | ||
return midpoint; | ||
} | ||
function point (point) { | ||
return { | ||
type: 'Point', | ||
coordinates: point | ||
} | ||
} | ||
function polygonToWorld (transformArgs, points, maxOffsetPercentage = 0.01, maxDepth = 8) { | ||
const worldPoints = points | ||
.map((point) => ({ | ||
image: point, | ||
world: toWorld(transformArgs, point) | ||
})); | ||
// if (maxOffsetPercentage > 0) | ||
const segments = Array.from(Array(worldPoints.length - 1)) | ||
.map((_, index) => ({ | ||
from: worldPoints[index], | ||
to: worldPoints[index + 1] | ||
})); | ||
const segmentsWithMidpoints = segments | ||
.map((segment) => addMidpoints(transformArgs, segment, maxOffsetPercentage, maxDepth)) | ||
.flat(Infinity); | ||
return { | ||
type: 'Polygon', | ||
coordinates: [ | ||
[ | ||
segmentsWithMidpoints[0].from.world, | ||
...segmentsWithMidpoints.map((segment) => segment.to.world) | ||
] | ||
] | ||
} | ||
} | ||
function addMidpoints (transformArgs, segment, maxOffsetPercentage, maxDepth, depth = 0) { | ||
const imageMidpoint = [ | ||
(segment.from.image[0] + segment.to.image[0]) / 2, | ||
(segment.from.image[1] + segment.to.image[1]) / 2 | ||
]; | ||
const segmentWorldMidpoint = midpoint(point(segment.from.world), point(segment.to.world)); | ||
const actualWorldMidpoint = point(toWorld(transformArgs, imageMidpoint)); | ||
const distanceSegment = distance(point(segment.from.world), point(segment.to.world)); | ||
const distanceMidpoints = distance(segmentWorldMidpoint, actualWorldMidpoint); | ||
if (distanceMidpoints / distanceSegment > maxOffsetPercentage && depth < maxDepth) { | ||
const newSegmentMidpoint = { | ||
image: imageMidpoint, | ||
world: actualWorldMidpoint.coordinates | ||
}; | ||
return [ | ||
addMidpoints(transformArgs, { from: segment.from, to: newSegmentMidpoint }, maxOffsetPercentage, depth + 1), | ||
addMidpoints(transformArgs, { from: newSegmentMidpoint, to: segment.to }, maxOffsetPercentage, depth + 1) | ||
] | ||
} else { | ||
return segment | ||
} | ||
} | ||
export { createTransformer, polygonToWorld, toImage, toWorld }; | ||
//# sourceMappingURL=index.js.map |
{ | ||
"name": "@allmaps/transform", | ||
"version": "1.0.0-alpha.3", | ||
"version": "1.0.0-alpha.4", | ||
"author": { | ||
@@ -12,4 +12,4 @@ "name": "Bert Spaan", | ||
"module": "dist/esm/index.js", | ||
"unpkg": "dist/transform.min.js", | ||
"jsdelivr": "dist/transform.min.js", | ||
"unpkg": "dist/allmaps-transform.min.js", | ||
"jsdelivr": "dist/allmaps-transform.min.js", | ||
"files": [ | ||
@@ -40,6 +40,9 @@ "dist" | ||
}, | ||
"dependencies": {}, | ||
"dependencies": { | ||
"@turf/distance": "^6.3.0", | ||
"@turf/midpoint": "^6.3.0" | ||
}, | ||
"engines": { | ||
"node": ">=12" | ||
"node": ">=14" | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
308329
1830
2
+ Added@turf/distance@^6.3.0
+ Added@turf/midpoint@^6.3.0
+ Added@turf/bearing@6.5.0(transitive)
+ Added@turf/destination@6.5.0(transitive)
+ Added@turf/distance@6.5.0(transitive)
+ Added@turf/helpers@6.5.0(transitive)
+ Added@turf/invariant@6.5.0(transitive)
+ Added@turf/midpoint@6.5.0(transitive)