What is cheap-ruler?
The cheap-ruler npm package provides fast and accurate approximations for common geospatial calculations. It is designed to be efficient and lightweight, making it suitable for applications that require quick distance and area calculations, point projections, and bounding box manipulations.
What are cheap-ruler's main functionalities?
Distance Calculation
Calculates the distance between two points. The example calculates the distance in miles between two coordinates.
const CheapRuler = require('cheap-ruler');
const ruler = new CheapRuler(35.05, 'miles');
const distance = ruler.distance([30.5, 50.5], [30.51, 50.49]);
console.log(distance);
Area Calculation
Calculates the area of a polygon. The example calculates the area in square miles of a polygon defined by a set of coordinates.
const CheapRuler = require('cheap-ruler');
const ruler = new CheapRuler(35.05, 'miles');
const area = ruler.area([[30.5, 50.5], [30.51, 50.49], [30.52, 50.48], [30.5, 50.5]]);
console.log(area);
Point Projection
Projects a point to a new location given a distance and bearing. The example projects a point 10 miles to the east (90 degrees) from the original point.
const CheapRuler = require('cheap-ruler');
const ruler = new CheapRuler(35.05, 'miles');
const point = ruler.destination([30.5, 50.5], 10, 90);
console.log(point);
Bounding Box Calculation
Calculates a bounding box around a point given a buffer distance. The example calculates a bounding box 10 miles around the given point.
const CheapRuler = require('cheap-ruler');
const ruler = new CheapRuler(35.05, 'miles');
const bbox = ruler.bufferBBox([30.5, 50.5], 10);
console.log(bbox);
Other packages similar to cheap-ruler
turf
Turf is a comprehensive geospatial analysis library for JavaScript. It provides a wide range of geospatial functions, including distance and area calculations, point projections, and more. Compared to cheap-ruler, Turf offers more extensive functionality but may be less performant for simple tasks.
geolib
Geolib is a library for geospatial calculations in JavaScript. It includes functions for distance and area calculations, point projections, and more. Geolib is similar to cheap-ruler in terms of functionality but may not be as optimized for performance.
geodesy
Geodesy is a library for geodesic calculations in JavaScript. It provides tools for distance and area calculations, point projections, and more. Geodesy focuses on high-precision calculations, which may be more accurate but slower compared to cheap-ruler.
cheap-ruler

A collection of very fast approximations to common geodesic measurements.
Useful for performance-sensitive code that measures things on a city scale. Can be an order of magnitude faster than corresponding Turf methods.
The approximations are based on the WGS84 ellipsoid model of the Earth, projecting coordinates to a flat surface that approximates the ellipsoid around a certain latitude.
For distances under 500 kilometers and not on the poles,
the results are very precise — within 0.1% margin of error
compared to Vincenti formulas,
and usually much less for shorter distances.
Usage
var ruler = new CheapRuler(35.05, 'miles');
...
var distance = ruler.distance([30.51, 50.32], [30.52, 50.312]);
var lineLength = ruler.lineDistance(line.geometry.coordinates);
var bbox = ruler.bufferPoint([30.5, 50.5], 0.01);
Note: to get the full performance benefit,
create a ruler object only once per a general area of calculation,
and then reuse it as much as possible.
Don't create a new ruler for every calculation.
Creating a ruler object
new CheapRuler(latitude[, units])
Creates a ruler object that will approximate measurements around the given latitude.
Units are one of: kilometers
(default), miles
, nauticalmiles
, meters
, yards
, feet
, inches
.
const ruler = new CheapRuler(50.5, 'meters');
CheapRuler.fromTile(y, z[, units])
Creates a ruler object from tile coordinates (y
and z
).
const ruler = CheapRuler.fromTile(1567, 12);
Ruler methods
distance(a, b)
Given two points of the form [longitude, latitude]
, returns the distance.
const distance = ruler.distance([30.5, 50.5], [30.51, 50.49]);
bearing(a, b)
Returns the bearing between two points in angles.
const bearing = ruler.bearing([30.5, 50.5], [30.51, 50.49]);
destination(p, dist, bearing)
Returns a new point given distance and bearing from the starting point.
const point = ruler.destination([30.5, 50.5], 0.1, 90);
offset(p, dx, dy)
Returns a new point given easting and northing offsets from the starting point.
const point = ruler.offset([30.5, 50.5], 10, 5);
lineDistance(line)
Given a line (an array of points), returns the total line distance.
const length = ruler.lineDistance([
[-67.031, 50.458], [-67.031, 50.534],
[-66.929, 50.534], [-66.929, 50.458]
]);
area(polygon)
Given a polygon (an array of rings, where each ring is an array of points), returns the area.
Note that it returns the value in the specified units
(square kilometers by default) rather than square meters as in turf.area
.
const area = ruler.area([[
[-67.031, 50.458], [-67.031, 50.534], [-66.929, 50.534],
[-66.929, 50.458], [-67.031, 50.458]
]]);
pointToSegmentDistance(p, a, b)
Returns the distance from a point p
to a line segment a
to b
.
const distance = ruler.pointToSegmentDistance([-77.034076, 38.882017],
[-77.031669, 38.878605], [-77.029609, 38.881946]);
along(line, dist)
Returns the point at a specified distance along the line.
const point = ruler.along(line, 2.5);
pointOnLine(line, p)
Returns an object of the form {point, index, t}
, where point
is closest point on the line from the given point,
index
is the start index of the segment with the closest point, and t
is a parameter from 0 to 1 that indicates
where the closest point is on that segment.
const point = ruler.pointOnLine(line, [-67.04, 50.5]).point;
lineSlice(start, stop, line)
Returns a part of the given line between the start and the stop points (or their closest points on the line).
const part = ruler.lineSlice([-67.04, 50.5], [-67.05, 50.56], line);
lineSliceAlong(startDist, stopDist, line)
Returns a part of the given line between the start and the stop points indicated by distance along the line.
const part = ruler.lineSliceAlong(10, 20, line);
bufferPoint(p, buffer)
Given a point, returns a bounding box object ([w, s, e, n]
) created from the given point buffered by a given distance.
const bbox = ruler.bufferPoint([30.5, 50.5], 0.01);
bufferBBox(bbox, buffer)
Given a bounding box, returns the box buffered by a given distance.
const bbox = ruler.bufferBBox([30.5, 50.5, 31, 51], 0.2);
insideBBox(p, bbox)
Returns true if the given point is inside in the given bounding box, otherwise false.
const inside = ruler.insideBBox([30.5, 50.5], [30, 50, 31, 51]);
Units conversion
Multipliers for converting between units are also exposed in CheapRuler.units
:
50 * CheapRuler.units.yards / CheapRuler.units.meters;
If you don't specify units when creating a ruler object,
you can use these constants to convert return values (using multiplication)
and input arguments (using division) to any units:
const distanceInFeet = ruler.distance(a, b) * CheapRuler.units.feet;
const box = ruler.bufferPoint(p, 200 / CheapRuler.units.inches);
Install
Precision
A table that shows the margin of error for ruler.distance
compared to node-vincenty
(a state of the art distance formula):
1km | 0% | 0% | 0% | 0% | 0% | 0% | 0% | 0% | 0% |
100km | 0% | 0% | 0% | 0% | 0% | 0% | 0% | 0.01% | 0.03% |
500km | 0.01% | 0.01% | 0.01% | 0.01% | 0.02% | 0.04% | 0.08% | 0.2% | 0.83% |
1000km | 0.03% | 0.03% | 0.04% | 0.06% | 0.1% | 0.17% | 0.33% | 0.8% | 3.38% |
Errors for all other methods are similar.
Related