# Geodart

A geospatial library for Dart. Designed primarily around vector features, this library provides a simple interface for working with geographic data.

It's based heavily on the geojson specification, but has been extended to add functionality directly to the feature types.

## Conversions

You can convert between different units with the `conversions`

library.

Types of conversions:

**Distance**: conversions between meters, kilometers, and miles, etc.**Area**: conversions between square meters, square kilometers, and square miles, etc.**Angle**: conversions between degrees, radians, and gradians, etc.

Here's an example:

```
import 'package:geodart/conversions.dart';
// Ten miles to kilometers
convertDistance(10, DistanceUnits.miles, DistanceUnits.kilometers); // returns 16.09344
// Ten degrees to radians
convertAngle(10, AngleUnits.degrees, AngleUnits.radians); // returns 0.17453292519943295
// Ten acres to square miles
convertArea(10, AreaUnits.acres, AreaUnits.squareMiles); // returns 0.004046856
```

There are some static units that are available with the type of `DistanceUnit`

, `AngleUnit`

and `AreaUnit`

. There are some preset units that are available with these types:

`DistanceUnit`

The following are the available units for length and distance:

`DistanceUnits.meters`

`DistanceUnits.kilometers`

`DistanceUnits.miles`

`DistanceUnits.feet`

`DistanceUnits.yards`

`DistanceUnits.nauticalMiles`

`DistanceUnits.millimeters`

`DistanceUnits.centimeters`

`AngleUnit`

The following are the available units for angles:

`AngleUnits.degrees`

`AngleUnits.radians`

`AngleUnits.gradians`

`AngleUnits.turns`

`AngleUnits.arcSeconds`

`AngleUnits.arcMinutes`

`AngleUnits.milliradians`

`AreaUnit`

The following are the available units for area:

`AreaUnits.squareMeters`

`AreaUnits.squareKilometers`

`AreaUnits.squareMiles`

`AreaUnits.acres`

`AreaUnits.hectares`

`AreaUnits.squareFeet`

`AreaUnits.squareYards`

`AreaUnits.squareInches`

## Geometries

To use this library, you'll need to get familiar with the feature types. All other actions taken depend on using the proper feature types. These feature types are very similar to the ones used in the geojson specification.

I'll admit, the feature coordinates are a bit of a mess. I'm working on a better way to handle this.

The following features are included in this library:

The package also provides a `Feature`

class, which is a
abstract class that can be extended to create new feature types.

Positions are stored using `Coordinate`

objects, which has a variety of
convenience methods for working with coordinates.

Bounding boxes (generally used as the minimum surrounding area of a `Feature`

) are stored
using `BoundingBox`

objects, which has a variety of convenience methods
for working with bounding boxes.

### Feature Collection

A `FeatureCollection`

is a collection of
`Feature`

objects.

It functions very similarly to a `List`

of `Feature`

objects,
but might extended to include additional properties in the future.

**Constructors**

`FeatureCollection.fromJson(Map<String, dynamic> json)`

- Creates a`FeatureCollection`

from a JSON object. Automatically converts features from GeoJSON to their respective types.`FeatureCollection.fromWKT(String wkt)`

- Creates a`FeatureCollection`

from a Well-Known Text string.

**Methods**

`toJson()`

- Returns a JSON object representing the`FeatureCollection`

. Automatically converts features to GeoJSON.`nearestPointTo(Point point)`

- Returns the nearest`Point`

in the`FeatureCollection`

to the given point.`explode()`

- Returns a`FeatureCollection`

of`Point`

objects, one for each coordinate in each geometry in the`FeatureCollection`

.`isCollectionOf(String type)`

- Returns true if the`FeatureCollection`

contains only features of the given type.

**Properties**

`features`

- A`List`

of`Feature`

objects.`type`

- The type of the`FeatureCollection`

. Always`"FeatureCollection"`

.`bbox`

- The``BoundingBox``

of the`FeatureCollection`

.`envelope`

- A`Polygon`

representing the envelope of the`FeatureCollection`

.`center`

- The`Point`

representing the center of the`FeatureCollection`

.`isEmpty`

- Whether or not the`FeatureCollection`

is empty.`convexHull`

- The smallest`Polygon`

representing the convex hull of the`FeatureCollection`

.

### Feature

A `Feature`

is an abstract class that can be extended to create new feature types.

**Because this class is abstract, you cannot instantiate it directly.**

**Methods**

`explode()`

- Returns a List of`Point`

objects, one for each coordinate in the`Feature`

.`toJson()`

- Returns a JSON object representing the`Feature`

. Automatically converts features to GeoJSON.`toWKT()`

- Returns a WKT string representing the`Feature`

.

**Properties**

`type`

- The type of the`Feature`

.`bbox`

- The``BoundingBox``

of the`Feature`

.`center`

- The`Point`

representing the center of the`Feature`

.

### Point

A `Point`

is a single position. It is represented by a `Coordinate`

object.

**Constructors**

`Point.fromJson(Map<String, dynamic> json)`

- Creates a`Point`

from a`Map`

of GeoJSON data.`Point.fromLngLat(num lng, num lat)`

- Creates a`Point`

from a`num`

longitude and latitude.`Point.fromWKT(String wkt)`

- Creates a`Point`

from a Well-Known Text string.`Point.random()`

- Creates a`Point`

at a random location within the`-180, 180`

x`-90, 90`

bounding box.

**Methods**

`explode()`

- Returns a`List`

of itself.`toJson()`

- Returns a`Map`

of GeoJSON data.`toWKT()`

- Returns a Well-Known Text string representing the`Point`

.`isContainedIn(Feature feature)`

- Returns true if the`Point`

is contained within the given`Polygon`

or`MultiPolygon`

.`buffer(double distance, {DistanceUnit unit = DistanceUnits.meters, int steps = 40})`

- Returns a`Polygon`

that is the buffer of the`Point`

of the given distance.

**Properties**

`coordinates`

- The`Coordinate`

of the`Point`

.`type`

- The type of the`Point`

. Always`"Point"`

.`properties`

- A`Map`

of properties.`bbox`

- a`BoundingBox`

of the`Point`

.`center`

- The`Point`

representing the center of the`Point`

, which is same as the point itself.`lat`

- The latitude of the`Point`

.`lng`

- The longitude of the`Point`

.

### Multi Point

A `MultiPoint`

is a collection of `Coordinate`

objects, represented by individual and non-connected points.

**Constructors**

`MultiPoint.fromJson(Map<String, dynamic> json)`

- Creates a`MultiPoint`

from a`Map`

of GeoJSON data.`MultiPoint.fromWKT(String wkt)`

- Creates a`MultiPoint`

from a Well-Known Text string.

**Methods**

`explode()`

- Returns a`List`

of`Point`

objects.`toJson()`

- Returns a`Map`

of GeoJSON data.`toWKT()`

- Returns a Well-Known Text string representing the`MultiPoint`

.`union({MultiPoint? multi, Point? point})`

- Merges the`MultiPoint`

with another`MultiPoint`

or`Point`

.`flatten()`

- Returns a`List`

of`Point`

objects.

**Properties**

`coordinates`

- A`List`

of`Coordinate`

objects.`type`

- The type of the`MultiPoint`

. Always`"MultiPoint"`

.`properties`

- A`Map`

of properties.`bbox`

- a`BoundingBox`

of the`MultiPoint`

.`center`

- The`Point`

representing the center of the`MultiPoint`

.

### Line String

A `LineString`

is a collection of `Coordinate`

objects that form a line.

**Constructors**

`LineString.fromJson(Map<String, dynamic> json)`

- Creates a`LineString`

from a`Map`

of GeoJSON data.`LineString.fromWkt(String wkt)`

- Creates a`LineString`

from a Well-Known Text string.`LineString.random({int length})`

- Creates a`LineString`

at a random location within the`-180, 180`

x`-90, 90`

bounding box with a given number of points (defaults to 2).

**Methods**

`along(distance)`

- Returns a`Point`

at the specified distance along the line.`explode()`

- Returns a`List`

of`Point`

objects that make up the LineString.`toJson()`

- Returns a GeoJSON`Map`

of the LineString.`toPolygon()`

- Returns a`Polygon`

that is the same as the LineString. LineString must be closed, or an exception will be thrown.`toWKT()`

- Returns a`String`

of the LineString in WKT format.`pointAt(double percentage)`

- Returns a`Point`

at the specified percentage along the line.`reverse()`

- Returns a`LineString`

that is the reverse of the original LineString.`isParallelTo(LineString line)`

- Returns`true`

if the LineString is parallel to the specified LineString, or all segments are parallel in order or reverse order.`intersections(LineString line)`

- Returns a`FeatureCollection`

of`Point`

objects where the LineString intersects the specified LineString.`contains(Point point)`

- Returns`true`

if the LineString contains the specified`Point`

.

**Properties**

`coordinates`

- A`List`

of`Coordinate`

objects that make up the LineString.`type`

- The type of the LineString. Always`"LineString"`

.`isClosedRing`

- A boolean indicating whether the LineString is a closed ring.`length`

- The length (in meters) of the LineString.`properties`

- A`Map`

of properties.`bbox`

- a`BoundingBox`

of the`LineString`

.`segments`

- A`List`

of`LineString`

objects that make up the LineString.`midpoint`

- Returns a`Point`

at the midpoint of the LineString.`center`

- The`Point`

representing the center of the`LineString`

's coordinates.`bearing`

- The bearing of the`LineString`

. If more than 2 coordinates are provided, 0.0 is returned.`slope`

- The slope of the`LineString`

. If more than 2 coordinates are provided, it uses the first and last coordinates.

### Multi Line String

A `MultiLineString`

is a collection of `Coordinate`

objects that form multiple separate LineStrings with one set of shared properties.

**Constructor**

`MultiLineString.fromJson(Map<String, dynamic> json)`

- Creates a`MultiLineString`

from a`Map`

of GeoJSON data.`MultiLineString.fromWkt(String wkt)`

- Creates a`MultiLineString`

from a Well-Known Text string.`MultiLineString.random({int count, int length})`

- Creates a`MultiLineString`

at a random location within the`-180, 180`

x`-90, 90`

bounding box, with a line count (count) and a number of points in each line (length).

**Methods**

`explode()`

- Returns a`List`

of`LineString`

objects.`toJson()`

- Returns a`Map`

of GeoJSON data.`toWKT()`

- Returns a Well-Known Text string representing the`MultiLineString`

.`union(MultiLineString other)`

- Merges the`MultiLineString`

with another`MultiLineString`

.`flatten()`

- Returns a`List`

of`LineString`

objects.

**Properties**

`coordinates`

- A nested`List`

of`Coordinate`

objects.`type`

- The type of the`MultiLineString`

. Always`"MultiLineString"`

.`properties`

- A`Map`

of properties.`bbox`

- a`BoundingBox`

of the`MultiLineString`

.

### Polygon

A `Polygon`

is a collection of ``LinearRing``

(#Linear Ring) objects that form a closed ring. The first LinearRing in the list is the outer ring, and any subsequent LinearRings are holes. Holes should be contained within the outer ring - if they are not, some algorithms may not work correctly. A Polygon should also not intersect itself - again, some algorithms may not work correctly if this is not the case.

**Constructors**

`Polygon.fromJson(Map<String, dynamic> json)`

- Creates a`Polygon`

from a`Map`

of GeoJSON data.`Polygon.fromWkt(String wkt)`

- Creates a`Polygon`

from a Well-Known Text string.

**Methods**

`explode()`

- Returns a`List`

of`Point`

objects.`toJson()`

- Returns a`Map`

of GeoJSON data.`toWKT()`

- Returns a Well-Known Text string representing the`Polygon`

.`toLineString()`

- Returns a`LineString`

that is the same geometry as the`Polygon`

.`contains(Point point)`

- Returns`true`

if the`Polygon`

contains the specified`Point`

.`intersects(Polygon poly)`

- Returns`true`

if the`Polygon`

intersects the specified`Polygon`

.

**Properties**

`coordinates`

- A`List`

of``LinearRing``

(#Linear Ring) objects.`type`

- The type of the`Polygon`

. Always`"Polygon"`

.`area`

- The are (in square meters) of the Polygon.`properties`

- A`Map`

of properties.`bbox`

- a`BoundingBox`

of the`Polygon`

.

### Multi Polygon

A `MultiPolygon`

is a collection of `Polygon`

geometries forming one MultiPolygon with shared properties.

**Constructors**

`MultiPolygon.fromJson(Map<String, dynamic> json)`

- Creates a`MultiPolygon`

from a`Map`

of GeoJSON data.`MultiPolygon.fromWkt(String wkt)`

- Creates a`MultiPolygon`

from a Well-Known Text string.

**Methods**

`explode()`

- Returns a`List`

of`Point`

objects.`toJson()`

- Returns a`Map`

of GeoJSON data.`toWKT()`

- Returns a Well-Known Text string representing the`MultiPolygon`

.`union({MultiPolygon? multi, Polygon? poly})`

- Merges the`MultiPolygon`

with another`MultiPolygon`

and/or`Polygon`

.`flatten()`

- Returns a`List`

of`Polygon`

objects.`toMultiLineString()`

- Returns a`MultiLineString`

that is the same geometry as the`MultiPolygon`

.`contains(Point point)`

- Returns`true`

if the`MultiPolygon`

contains the`Point`

.`intersects(poly: Polygon, multi: MultiPolygon)`

- Returns`true`

if this`MultiPolygon`

intersects the passed`Polygon`

or`MultiPolygon`

.

**Properties**

`coordinates`

- A`List`

of`Polygon`

objects.`type`

- The type of the`MultiPolygon`

. Always`"MultiPolygon"`

.`properties`

- A`Map`

of properties.`area`

- The are (in square meters) of the MultiPolygon.`bbox`

- a`BoundingBox`

of the`MultiPolygon`

.`hasSelfIntersections`

- Returns`true`

if any of the contained`LinearRing`

geometries intersect.

### Coordinate

A `Coordinate`

is a point in a two-dimensional Cartesian coordinate system.

**Constructors**

`Coordinate.fromJson(Map<String, dynamic> json)`

- Creates a`Coordinate`

from a`Map`

of GeoJSON data.`Coordinate.fromWkt(String wkt)`

- Creates a`Coordinate`

from a Well-Known Text string.`Coordinate.random()`

- Creates a`Coordinate`

at a random location.

**Methods**

`toJson()`

- Returns a`Map`

of GeoJSON data.`toWKT()`

- Returns a Well-Known Text string representing the`Coordinate`

.`toENU(Coordinate origin)`

- Returns the difference in 3 dimensional space (as`List<double>[xEast, yNorth, zUp]`

) between the`Coordinate`

and the passed`Coordinate`

origin.`distanceTo(Coordinate other)`

- Returns the distance (in meters) between the`Coordinate`

and another`Coordinate`

.`bearingTo(Coordinate other)`

- Returns the bearing (in degrees) between the`Coordinate`

and another`Coordinate`

.`destination(num distance, num bearing)`

- Returns a`Coordinate`

that is the same geometry as the`Coordinate`

but moved a given distance and bearing.`interpolate(Coordinate other, num fraction)`

- Returns a`Coordinate`

that is the same geometry as the`Coordinate`

but moved a given fraction of the distance and bearing to another`Coordinate`

.

**Properties**

`latitude`

- The latitude of the`Coordinate`

.`longitude`

- The longitude of the`Coordinate`

.`type`

- The type of the`Coordinate`

. Always`"Coordinate"`

.

`LinearRing`

A ``LinearRing``

(#Linear Ring) is a closed `LineString`

that is closed because the first and last coordinate are the same.

**Constructors**

`LinearRing.random()`

- Creates a``LinearRing``

(#Linear Ring) with 3 random`Coordinates`

.

**Methods**

`toLineString()`

- Returns a`LineString`

that is the same geometry as the``LinearRing``

(#Linear Ring).`reverse()`

- Returns a``LinearRing``

(#Linear Ring) that is the same geometry as the``LinearRing``

(#Linear Ring) but in reverse order.`explode()`

- Returns a`FeatureCollection`

of`Point`

objects.

**Properties**

`coordinates`

- A`List`

of`Coordinate`

objects.`type`

- The type of the``LinearRing``

(#Linear Ring). Always`"LinearRing"`

.`area`

- The are (in square meters) of the``LinearRing``

(#Linear Ring).`centroid`

- The`Coordinate`

that is the centroid of the``LinearRing``

(#Linear Ring).`bbox`

- a`BoundingBox`

of the``LinearRing``

(#Linear Ring).

### BoundingBox

A `BoundingBox`

is a rectangular area of the two-dimensional Cartesian coordinate system.
Generally, it is used to represent the smallest possible bounds of a `Feature`

in lat/long space.

**Constructors**

`BoundingBox.fromCoordinates(List<Coordinate> points)`

- Creates a`BoundingBox`

from a`List`

of`Coordinate`

objects.`BoundingBox.empty()`

- Creates an empty`BoundingBox`

.`BoundingBox.fromPoints(List<Point> points)`

- Creates a`BoundingBox`

from a`List`

of`Point`

objects.

**Methods**

`toList()`

- Returns a`List`

of GeoJSON data.`toPolygon()`

- Returns a`Polygon`

that is the same geometry as the`BoundingBox`

.

**Properties**

`minLong`

- The minimum longitude of the`BoundingBox`

.`minLat`

- The minimum latitude of the`BoundingBox`

.`maxLong`

- The maximum longitude of the`BoundingBox`

.`maxLat`

- The maximum latitude of the`BoundingBox`

.`type`

- The type of the`BoundingBox`

. Always`"BoundingBox"`

.`center`

- The`Coordinate`

center of the`BoundingBox`

.`square`

- The`BoundingBox`

, but made square.

## Usage

**Measure the distance between two points.**

```
import 'package:geodart/measurements.dart';
import 'package:geodart/geometries.dart';
double distanceBetween = distance(
Point.fromLngLat(1.0, 1.0),
Point.fromLngLat(2.0, 2.0),
);
```

Under the hood, this uses the coordinate `distanceTo()`

function, and could be very easily replaced with a different algorithm.
I prefer the `distanceTo()`

function because it is more explicit and easier to read.

```
import 'package:geodart/geometries.dart';
double distanceBetween = Coordinate(1.0, 1.0).distanceTo(Coordinate(2.0, 2.0));
```

**Measure the area of a polygon.**

```
import 'package:geodart/geometries.dart';
Polygon polygon = Polygon.fromJson(
{
'type': 'Polygon',
'coordinates': [
[
[1.0, 1.0],
[2.0, 1.0],
[2.0, 2.0],
[1.0, 1.0],
],
],
}
);
print(polygon.area);
```

**Measure the length of a LineString.**

`LineString`

length is calculated on the fly.

```
import 'package:geodart/geometries.dart';
LineString lineString = LineString.fromJson(
{
'type': 'LineString',
'coordinates': [
[1.0, 1.0],
[2.0, 2.0],
],
}
);
print(lineString.length);
```

## Additional information

### License

This library is free software under the terms of the MIT license. See the LICENSE file for more details.

### Contributing

If you have any questions or comments, please open an issue on the Github repository.

If you want to make a pull request, please open a pull request on the Github repository. Please make sure to include a test suite. I make no promises that I will accept pull requests, but I will try my best to keep the code up to date.

## Libraries

- conversions
- Conversions
- geometries
- Features
- measurements
- A collection of measurement functions.