Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Misc doc changes #7

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .formatter.exs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# Used by "mix format"
[
inputs: ["mix.exs", "{config,lib,test}/**/*.{ex,exs}"]
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]
23 changes: 15 additions & 8 deletions .gitignore
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,23 +1,30 @@
# The directory Mix will write compiled artifacts to.
/_build
/_build/

# If you run "mix test --cover", coverage assets end up here.
/cover
/cover/

# The directory Mix downloads your dependencies sources to.
/deps
/deps/

# Where 3rd-party dependencies like ExDoc output generated docs.
/doc
# Where third-party dependencies like ExDoc output generated docs.
/doc/

# Ignore .fetch files in case you like to edit your project deps locally.
/.fetch

# If the VM crashes, it generates a dump, let's ignore it too.
erl_crash.dump

# Also ignore archive artifacts (built via "mix archive.build").
*.ez

.elixir_ls
kianmeng marked this conversation as resolved.
Show resolved Hide resolved
# Ignore package tarball (built via "mix hex.build").
envelope-*.tar

.DS_Store
# Temporary files, for example, from tests.
/tmp/

tags
# Misc.
.DS_Store
.elixir_ls/
Empty file modified .travis.yml
100755 → 100644
Empty file.
2 changes: 1 addition & 1 deletion LICENSE → LICENSE.md
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
MIT License
# MIT License

Copyright (c) 2017 Powell Kinney

Expand Down
21 changes: 17 additions & 4 deletions README.md
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
# Envelope

[![CI](https://github.com/pkinney/envelope_ex/actions/workflows/ci.yaml/badge.svg)](https://github.com/pkinney/envelope_ex/actions/workflows/ci.yaml)
[![Hex.pm](https://img.shields.io/hexpm/v/envelope.svg)](https://hex.pm/packages/envelope)
[![Hex Version](https://img.shields.io/hexpm/v/envelope.svg)](https://hex.pm/packages/envelope)
[![Hex Docs](https://img.shields.io/badge/hex-docs-lightgreen.svg)](https://hexdocs.pm/envelope/)
[![Total Download](https://img.shields.io/hexpm/dt/envelope.svg)](https://hex.pm/packages/envelope)
[![License](https://img.shields.io/hexpm/l/envelope.svg)](https://github.com/pkinney/envelope_ex/blob/master/LICENSE.md)
[![Last Updated](https://img.shields.io/github/last-commit/pkinney/envelope_ex.svg)](https://github.com/pkinney/envelope_ex/commits/master)

A library for calculating envelopes (axis-aligned bounding boxes) of geometries and tools to compare them.
This is most useful as an approximation of spacial relationships between more
Expand All @@ -11,7 +15,9 @@ complicated geometries.

```elixir
defp deps do
[{:envelope, "~> 1.3"}]
[
{:envelope, "~> 1.3"}
]
end
```

Expand Down Expand Up @@ -52,7 +58,7 @@ Envelope.contains?(
# => false
```

## Applicaiton
## Application

In the context of a larger Geometry/GIS application, Envelopes can be used to
drastically decrease processing overhead for comparing two geometries that are
Expand Down Expand Up @@ -88,8 +94,15 @@ def intersect?(poly1, poly2) do
end
```

or more concisely
or more concisely:

```elixir
Envelope.intersects?(Envelope.from_geo(poly1), Envelope.from_geo(poly2)) && Topo.intersects?(poly1, poly2)
```

## Copyright and License

Copyright (c) 2017 Powell Kinney

This work is free. You can redistribute it and/or modify it under the
terms of the MIT License. See the [LICENSE.md](./LICENSE.md) file for more details.
Empty file modified bench/envelope_bench.exs
100755 → 100644
Empty file.
Empty file modified bench/envelope_compare_bench.exs
100755 → 100644
Empty file.
Empty file modified bench/shapes/cities.json
100755 → 100644
Empty file.
Empty file modified bench/shapes/counties.json
100755 → 100644
Empty file.
Empty file modified bench/shapes/interstates.json
100755 → 100644
Empty file.
Empty file modified bench/shapes/states.json
100755 → 100644
Empty file.
Empty file modified config/config.exs
100755 → 100644
Empty file.
59 changes: 48 additions & 11 deletions lib/envelope.ex
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
defmodule Envelope do
@moduledoc ~S"""
A library for calculating envelopes of geometries and tools to compare them.

This is most useful as an approximation of spacial relationships between more
complicated geometries.

Expand All @@ -10,12 +11,13 @@ defmodule Envelope do
iex> Envelope.from_geo( %Geo.LineString{coordinates: [{1, 3}, {2, -1}, {0, -1}, {1, 3}]} )
%Envelope{ min_x: 0, min_y: -1, max_x: 2, max_y: 3 }

You can also expand an existing Envelope with a geometry or another Envelope
You can also expand an existing Envelope with a geometry or another Envelope:

iex> a = Envelope.from_geo( %Geo.Polygon{coordinates: [[{2, -2}, {20, -2}, {11, 11}, {2, -2}]]} )
...> b = %Geo.LineString{coordinates: [{1, 3}, {2, -1}, {0, -1}, {1, 3}]}
...> Envelope.expand(a, b)
%Envelope{ min_x: 0, min_y: -2, max_x: 20, max_y: 11 }

"""

defstruct min_x: 0, min_y: 0, max_x: 0, max_y: 0
Expand Down Expand Up @@ -45,6 +47,7 @@ defmodule Envelope do
coordinates.

## Examples

iex> Envelope.from_geo %{coordinates: [{11, 10}, {4, 2.5}, {16, 2.5}, {11, 10}]}
%Envelope{ max_x: 16, max_y: 10, min_x: 4, min_y: 2.5 }

Expand All @@ -56,6 +59,7 @@ defmodule Envelope do

iex> Envelope.from_geo {1, 3}
%Envelope{ min_x: 1, min_y: 3, max_x: 1, max_y: 3 }

"""
@spec from_geo(points()) :: t()
def from_geo({x, y}) when is_number(x) and is_number(y),
Expand Down Expand Up @@ -86,6 +90,7 @@ defmodule Envelope do
- `Geo.Polygon` will be returned when an envelope has non-zeron area

## Examples

iex> Envelope.to_geo %Envelope{ max_x: 16, max_y: 10, min_x: 4, min_y: 2.5 }
%Geo.Polygon{coordinates: [[{4, 2.5}, {4, 10}, {16, 10}, {16, 2.5}, {4, 2.5}]]}

Expand All @@ -97,6 +102,7 @@ defmodule Envelope do

iex> Envelope.to_geo %Envelope{ min_x: 1, min_y: 3, max_x: 1, max_y: 3 }
%Geo.Point{coordinates: {1, 3}}

"""
@spec to_geo(t()) :: %Geo.Polygon{} | %Geo.Point{} | %Geo.LineString{}
def to_geo(%Envelope{min_x: x, min_y: y, max_x: x, max_y: y}),
Expand All @@ -122,34 +128,40 @@ defmodule Envelope do
}

@doc ~S"""
Returns an `Envelope` that represents no extent at all. This is primarily
a convenience function for starting an expanding Envelope. Internally,
"empty" Envelopes are represented with `nil` values for all extents.
Returns an `Envelope` that represents no extent at all.

This is primarily a convenience function for starting an expanding Envelope.
Internally, "empty" Envelopes are represented with `nil` values for all
extents.

Note that there is a important distinction between an empty Envelope and
an Envelope around a single Point (where the min and max for each axis are
real numbers but may represent zero area).

## Examples

iex> Envelope.empty
%Envelope{max_x: nil, max_y: nil, min_x: nil, min_y: nil}

iex> Envelope.empty |> Envelope.empty?
true

"""
@spec empty() :: t()
def empty, do: %Envelope{min_x: nil, min_y: nil, max_x: nil, max_y: nil}

@doc ~S"""
Returns `true` if the given envelope is empty (has non-existent extent),
otherwise `false`
otherwise `false`.

## Examples

iex> Envelope.empty |> Envelope.empty?
true

iex> %Envelope{ min_x: 0, min_y: -1, max_x: 2, max_y: 3 } |> Envelope.empty?
false

"""
@spec empty?(t()) :: boolean()
def empty?(%Envelope{min_x: nil, min_y: nil, max_x: nil, max_y: nil}), do: true
Expand All @@ -159,6 +171,7 @@ defmodule Envelope do
Returns a new Envelope that is expanded to include an additional geometry.

## Examples

iex> a = Envelope.from_geo(%Geo.Polygon{coordinates: [[{2, -2}, {20, -2}, {11, 11}, {2, -2}]]})
...> b = %Geo.LineString{coordinates: [{1, 3}, {2, -1}, {0, -1}, {1, 3}]}
...> Envelope.expand(a, b)
Expand All @@ -177,6 +190,7 @@ defmodule Envelope do

iex> Envelope.expand(Envelope.empty, Envelope.empty) |> Envelope.empty?
true

"""
@spec expand(t(), point() | t() | points()) :: t()
def expand(%Envelope{} = env1, %Envelope{} = env2) do
Expand Down Expand Up @@ -204,11 +218,13 @@ defmodule Envelope do
in each axis by `radius`.

## Examples

iex> Envelope.expand_by(Envelope.from_geo(%Geo.Polygon{coordinates: [[{2, -2}, {20, -2}, {11, 11}, {2, -2}]]}), 3)
%Envelope{ min_x: -1, min_y: -5, max_x: 23, max_y: 14 }

iex> Envelope.expand_by(Envelope.empty, 4) |> Envelope.empty?
true

"""
@spec expand_by(t(), number()) :: t()
def expand_by(%Envelope{} = env, radius) when is_number(radius) and radius >= 0 do
Expand All @@ -230,21 +246,26 @@ defmodule Envelope do
Simple distance from the left bounadary to the right boundary of the Envelope.

## Examples

iex> Envelope.width(Envelope.from_geo(%Geo.Polygon{coordinates: [[{2, -2}, {20, -2}, {11, 11}, {2, -2}]]}))
18

"""
@spec width(t()) :: number()
def width(%Envelope{} = env) do
env.max_x - env.min_x
end

@doc ~S"""
When an Envelope's coordinates are in degress of longitude and latitude, calculates the
great circle distance between the center of the east and west extent in meters.
When an Envelope's coordinates are in degrees of longitude and latitude,
calculates the great circle distance between the center of the east and west
extent in meters.

## Examples

iex> Envelope.width_gc(Envelope.from_geo(%Geo.Polygon{coordinates: [[{2, -2}, {20, -2}, {11, 11}, {2, -2}]]})) |> round
1982362

"""
@spec width_gc(t()) :: number()
def width_gc(%Envelope{} = env) do
Expand All @@ -255,24 +276,29 @@ defmodule Envelope do
end

@doc ~S"""
Simple distance from the bottom bounadary to the top boundary of the Envelope.
Simple distance from the bottom boundary to the top boundary of the Envelope.

## Examples

iex> Envelope.height(Envelope.from_geo(%Geo.Polygon{coordinates: [[{2, -2}, {20, -2}, {11, 11}, {2, -2}]]}))
13

"""
@spec height(t()) :: number()
def height(%Envelope{} = env) do
env.max_y - env.min_y
end

@doc ~S"""
When an Envelope's coordinates are in degress of longitude and latitude, calculates the
great circle distance between the center of the north and south extent in meters.
When an Envelope's coordinates are in degrees of longitude and latitude,
calculates the great circle distance between the center of the north and
south extent in meters.

## Examples

iex> Envelope.height_gc(Envelope.from_geo(%Geo.Polygon{coordinates: [[{2, -2}, {20, -2}, {11, 11}, {2, -2}]]})) |> round
1445536

"""
@spec height_gc(t()) :: number()
def height_gc(%Envelope{} = env) do
Expand All @@ -283,20 +309,25 @@ defmodule Envelope do
Calculates the simple area of an Envelope.

## Examples

iex> Envelope.area(Envelope.from_geo(%Geo.Polygon{coordinates: [[{2, -2}, {20, -2}, {11, 11}, {2, -2}]]}))
234

"""
@spec area(t()) :: number()
def area(%Envelope{} = env) do
width(env) * height(env)
end

@doc ~S"""
Estimates the area of an Envelope in square meters when the Envelope's coordinates are in degress of longitude and latitude.
Estimates the area of an Envelope in square meters when the Envelope's
coordinates are in degrees of longitude and latitude.

## Examples

iex> Envelope.area_gc(Envelope.from_geo(%Geo.Polygon{coordinates: [[{2, -2}, {20, -2}, {11, 11}, {2, -2}]]})) |> round
2865575088701

"""
@spec area_gc(t()) :: number()
def area_gc(%Envelope{} = env) do
Expand Down Expand Up @@ -326,6 +357,7 @@ defmodule Envelope do
Returns whether one envelope fully contains another envelope or point.

## Examples

iex> Envelope.contains?(
...> %Envelope{ min_x: -1, min_y: -5, max_x: 23, max_y: 14 },
...> %Envelope{ min_x: 0, min_y: 3, max_x: 7, max_y: 4 })
Expand All @@ -340,6 +372,7 @@ defmodule Envelope do
...> %Geo.Polygon{ coordinates: [{-1, 3}, {-3, -1}, { 5, -3}, {4, 12}, {-2, 11}, {-1, 3}] },
...> {0, 11})
true

"""
@spec contains?(t() | points(), t() | points()) :: boolean()
def contains?(%Envelope{} = env, {x, y}) do
Expand All @@ -360,6 +393,7 @@ defmodule Envelope do
The inverse of the relationship tested by Envelope#contains?

## Examples

iex> Envelope.within?(
...> %Envelope{ min_x: 0, min_y: 3, max_x: 7, max_y: 4 },
...> %Envelope{ min_x: -1, min_y: -5, max_x: 23, max_y: 14 })
Expand All @@ -369,6 +403,7 @@ defmodule Envelope do
...> %Geo.Polygon{ coordinates: [{-1, 3}, {-3, -1}, { 5, -3}, {4, 12}, {-2, 11}, {-1, 3}] },
...> {0, 11})
false

"""
@spec within?(t() | points(), t() | points()) :: boolean()
def within?(a, b), do: contains?(b, a)
Expand All @@ -377,6 +412,7 @@ defmodule Envelope do
Returns whether two envelopes touch or intersect.

## Examples

iex> Envelope.intersects?(
...> %Envelope{ min_x: -1, min_y: -5, max_x: 23, max_y: 14 },
...> %Envelope{ min_x: 0, min_y: 3, max_x: 7, max_y: 4 })
Expand All @@ -386,6 +422,7 @@ defmodule Envelope do
...> %Envelope{ min_x: -1, min_y: 5, max_x: 23, max_y: 14 },
...> %Envelope{ min_x: 0, min_y: -3, max_x: 7, max_y: 4 })
false

"""
@spec intersects?(t() | points(), t() | points()) :: boolean()
def intersects?(%Envelope{} = env1, %Envelope{} = env2) do
Expand Down
Loading