{"id":13610026,"url":"https://github.com/mapbox/cheap-ruler","last_synced_at":"2025-04-12T22:32:32.331Z","repository":{"id":7413743,"uuid":"56320775","full_name":"mapbox/cheap-ruler","owner":"mapbox","description":"Fast approximations for common geodesic measurements 🌐","archived":false,"fork":false,"pushed_at":"2024-06-26T15:05:25.000Z","size":180,"stargazers_count":418,"open_issues_count":2,"forks_count":32,"subscribers_count":101,"default_branch":"main","last_synced_at":"2024-10-06T20:33:53.324Z","etag":null,"topics":["distance","fast","geodesy","javascript","library","measurements"],"latest_commit_sha":null,"homepage":"https://www.mapbox.com/blog/cheap-ruler/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mapbox.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-04-15T13:05:23.000Z","updated_at":"2024-09-10T08:39:12.000Z","dependencies_parsed_at":"2024-08-01T19:43:53.026Z","dependency_job_id":"6d8a6bc5-83f1-49de-bc87-be8371d47abd","html_url":"https://github.com/mapbox/cheap-ruler","commit_stats":{"total_commits":105,"total_committers":12,"mean_commits":8.75,"dds":"0.17142857142857137","last_synced_commit":"c34d08b9a4ff3b76939ca7992d1c6a29053278bf"},"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mapbox%2Fcheap-ruler","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mapbox%2Fcheap-ruler/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mapbox%2Fcheap-ruler/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mapbox%2Fcheap-ruler/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mapbox","download_url":"https://codeload.github.com/mapbox/cheap-ruler/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223549091,"owners_count":17163588,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["distance","fast","geodesy","javascript","library","measurements"],"created_at":"2024-08-01T19:01:40.455Z","updated_at":"2024-11-07T16:30:31.346Z","avatar_url":"https://github.com/mapbox.png","language":"JavaScript","readme":"# cheap-ruler [![Node](https://github.com/mapbox/cheap-ruler/actions/workflows/node.yml/badge.svg)](https://github.com/mapbox/cheap-ruler/actions/workflows/node.yml) [![](https://img.shields.io/badge/simply-awesome-brightgreen.svg)](https://github.com/mourner/projects)\n\nA collection of very fast approximations to common geodesic measurements.\nUseful for performance-sensitive code that measures things on a city scale. Can be an order of magnitude faster than corresponding [Turf](http://turfjs.org/) methods.\n\nThe approximations are based on the [WGS84 ellipsoid model of the Earth](https://en.wikipedia.org/wiki/Earth_radius#Meridional), projecting coordinates to a flat surface that approximates the ellipsoid around a certain latitude.\nFor distances under 500 kilometers and not on the poles,\nthe results are very precise — within [0.1% margin of error](#precision)\ncompared to [Vincenti formulas](https://en.wikipedia.org/wiki/Vincenty%27s_formulae),\nand usually much less for shorter distances.\n\n## Usage\n\n```js\nvar ruler = new CheapRuler(35.05, 'miles'); // calculations around latitude 35\n...\nvar distance = ruler.distance([30.51, 50.32], [30.52, 50.312]);\nvar lineLength = ruler.lineDistance(line.geometry.coordinates);\nvar bbox = ruler.bufferPoint([30.5, 50.5], 0.01);\n```\n\n**Note**: to get the full performance benefit,\ncreate a ruler object only once per a general area of calculation,\nand then reuse it as much as possible.\nDon't create a new ruler for every calculation.\n\n### Creating a ruler object\n\n#### new CheapRuler(latitude[, units])\n\nCreates a ruler object that will approximate measurements around the given latitude.\nUnits are one of: `kilometers` (default), `miles`, `nauticalmiles`, `meters`, `yards`, `feet`, `inches`.\n\n```js\nconst ruler = new CheapRuler(50.5, 'meters');\n````\n\n#### CheapRuler.fromTile(y, z[, units])\n\nCreates a ruler object from tile coordinates (`y` and `z`).\n\n```js\nconst ruler = CheapRuler.fromTile(1567, 12);\n```\n\n### Ruler methods\n\n#### distance(a, b)\n\nGiven two points of the form `[longitude, latitude]`, returns the distance.\n\n```js\nconst distance = ruler.distance([30.5, 50.5], [30.51, 50.49]);\n```\n\n#### bearing(a, b)\n\nReturns the bearing between two points in angles.\n\n```js\nconst bearing = ruler.bearing([30.5, 50.5], [30.51, 50.49]);\n```\n\n#### destination(p, dist, bearing)\n\nReturns a new point given distance and bearing from the starting point.\n\n```js\nconst point = ruler.destination([30.5, 50.5], 0.1, 90);\n```\n\n#### offset(p, dx, dy)\n\nReturns a new point given easting and northing offsets from the starting point.\n\n```js\nconst point = ruler.offset([30.5, 50.5], 10, 5); // 10km east and 5km north\n```\n\n#### lineDistance(line)\n\nGiven a line (an array of points), returns the total line distance.\n\n```js\nconst length = ruler.lineDistance([\n    [-67.031, 50.458], [-67.031, 50.534],\n    [-66.929, 50.534], [-66.929, 50.458]\n]);\n```\n\n#### area(polygon)\n\nGiven a polygon (an array of rings, where each ring is an array of points), returns the area.\nNote that it returns the value in the specified units\n(square kilometers by default) rather than square meters as in `turf.area`.\n\n```js\nconst area = ruler.area([[\n    [-67.031, 50.458], [-67.031, 50.534], [-66.929, 50.534],\n    [-66.929, 50.458], [-67.031, 50.458]\n]]);\n```\n\n#### pointToSegmentDistance(p, a, b)\n\nReturns the distance from a point `p` to a line segment `a` to `b`.\n\n```js\nconst distance = ruler.pointToSegmentDistance([-77.034076, 38.882017],\n    [-77.031669, 38.878605], [-77.029609, 38.881946]);\n````\n\n#### along(line, dist)\n\nReturns the point at a specified distance along the line.\n\n```js\nconst point = ruler.along(line, 2.5);\n```\n\n#### pointOnLine(line, p)\n\nReturns an object of the form `{point, index, t}`, where `point` is closest point on the line from the given point,\n`index` is the start index of the segment with the closest point, and `t` is a parameter from 0 to 1 that indicates\nwhere the closest point is on that segment.\n\n```js\nconst point = ruler.pointOnLine(line, [-67.04, 50.5]).point;\n```\n\n#### lineSlice(start, stop, line)\n\nReturns a part of the given line between the start and the stop points (or their closest points on the line).\n\n```js\nconst part = ruler.lineSlice([-67.04, 50.5], [-67.05, 50.56], line);\n```\n\n#### lineSliceAlong(startDist, stopDist, line)\n\nReturns a part of the given line between the start and the stop points indicated by distance along the line.\n\n```js\nconst part = ruler.lineSliceAlong(10, 20, line);\n```\n\n#### bufferPoint(p, buffer)\n\nGiven a point, returns a bounding box object (`[w, s, e, n]`) created from the given point buffered by a given distance.\n\n```js\nconst bbox = ruler.bufferPoint([30.5, 50.5], 0.01);\n```\n\n#### bufferBBox(bbox, buffer)\n\nGiven a bounding box, returns the box buffered by a given distance.\n\n```js\nconst bbox = ruler.bufferBBox([30.5, 50.5, 31, 51], 0.2);\n```\n\n#### insideBBox(p, bbox)\n\nReturns true if the given point is inside in the given bounding box, otherwise false.\n\n```js\nconst inside = ruler.insideBBox([30.5, 50.5], [30, 50, 31, 51]);\n```\n\n### Units conversion\n\nMultipliers for converting between units are also exposed in `CheapRuler.units`:\n\n```js\n// convert 50 meters to yards\n50 * CheapRuler.units.yards / CheapRuler.units.meters;\n```\n\nIf you don't specify units when creating a ruler object,\nyou can use these constants to convert return values (using multiplication)\nand input arguments (using division) to any units:\n\n```js\n// get distance between points in feet\nconst distanceInFeet = ruler.distance(a, b) * CheapRuler.units.feet;\n\n// make a bbox from a point with a 200 inch buffer\nconst box = ruler.bufferPoint(p, 200 / CheapRuler.units.inches);\n```\n\n## Install\n\n- NPM: `npm install cheap-ruler`\n- [Browser build on CDN (ESM)](https://esm.run/cheap-ruler)\n- [Browser build on CDN (UMD)](https://cdn.jsdelivr.net/npm/cheap-ruler/cheap-ruler.js)\n\n## Precision\n\nA table that shows the margin of error for `ruler.distance` compared to `node-vincenty`\n(a state of the art distance formula):\n\n| lat | 0\u0026deg; | 10\u0026deg; | 20\u0026deg; | 30\u0026deg; | 40\u0026deg; | 50\u0026deg; | 60\u0026deg; | 70\u0026deg; | 80\u0026deg; |\n| --- |  --- | --- | --- | --- | --- | --- | --- | --- | --- |\n| 1km | 0% | 0% | 0% | 0% | 0% | 0% | 0% | 0% | 0% |\n| 100km | 0% | 0% | 0% | 0% | 0% | 0% | 0% | 0.01% | 0.03% |\n| 500km | 0.01% | 0.01% | 0.01% | 0.01% | 0.02% | 0.04% | 0.08% | 0.2% | 0.83% |\n| 1000km | 0.03% | 0.03% | 0.04% | 0.06% | 0.1% | 0.17% | 0.33% | 0.8% | 3.38% |\n\nErrors for all other methods are similar.\n\n## Related\n\n- [cheap-ruler-cpp](https://github.com/mapbox/cheap-ruler-cpp) – C++ port of this library\n- [cheap-ruler-rs](https://github.com/vipera/cheap-ruler-rs) – Rust port of this library\n- [flat-projection](https://github.com/Turbo87/flat-projection-rs) – Rust library based on the same concept\n","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmapbox%2Fcheap-ruler","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmapbox%2Fcheap-ruler","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmapbox%2Fcheap-ruler/lists"}