# `AstroUtils.Vector`
[🔗](https://github.com/jakedjohnson/astro_utils/blob/v0.1.0/lib/astro_utils/vector.ex#L1)

3D vector operations on `{x, y, z}` tuples.

Vectors are plain three-element tuples of floats, so they are cheap to
build, pattern-match, and pass around. Components are unitless: the caller
decides whether a vector holds AU, kilometres, or a direction cosine.

Functions are total for finite float input; the only special case is
`normalize/1` on the zero vector, which returns the zero vector rather
than raising.

    iex> alias AstroUtils.Vector
    iex> Vector.cross({1.0, 0.0, 0.0}, {0.0, 1.0, 0.0})
    {0.0, 0.0, 1.0}

# `t`

```elixir
@type t() :: {float(), float(), float()}
```

A 3D vector as an `{x, y, z}` tuple.

# `add`

```elixir
@spec add(t(), t()) :: t()
```

Component-wise sum `a + b`.

## Examples

    iex> AstroUtils.Vector.add({1.0, 2.0, 3.0}, {4.0, 5.0, 6.0})
    {5.0, 7.0, 9.0}

# `cross`

```elixir
@spec cross(t(), t()) :: t()
```

Cross (vector) product `a × b`, following the right-hand rule.

The result is orthogonal to both inputs, and is the zero vector when the
inputs are parallel. The operation is anticommutative:
`cross(a, b) == negate(cross(b, a))`.

## Examples

    iex> AstroUtils.Vector.cross({1.0, 0.0, 0.0}, {0.0, 1.0, 0.0})
    {0.0, 0.0, 1.0}

    iex> AstroUtils.Vector.cross({1.0, 0.0, 0.0}, {2.0, 0.0, 0.0})
    {0.0, 0.0, 0.0}

# `dot`

```elixir
@spec dot(t(), t()) :: float()
```

Dot (scalar) product of two vectors.

For unit vectors the result is the cosine of the angle between them, so
`0.0` means orthogonal and `±1.0` means parallel or antiparallel.

## Examples

    iex> AstroUtils.Vector.dot({1.0, 2.0, 3.0}, {4.0, 5.0, 6.0})
    32.0

    iex> AstroUtils.Vector.dot({1.0, 0.0, 0.0}, {0.0, 1.0, 0.0})
    0.0

# `magnitude`

```elixir
@spec magnitude(t()) :: float()
```

Euclidean length (L2 norm) of a vector.

## Examples

    iex> AstroUtils.Vector.magnitude({3.0, 4.0, 0.0})
    5.0

    iex> AstroUtils.Vector.magnitude({0.0, 0.0, 0.0})
    0.0

# `negate`

```elixir
@spec negate(t()) :: t()
```

Reverse a vector's direction, preserving its magnitude.

## Examples

    iex> AstroUtils.Vector.negate({1.0, -2.0, 3.0})
    {-1.0, 2.0, -3.0}

# `normalize`

```elixir
@spec normalize(t()) :: t()
```

Scale a vector to unit length.

The zero vector has no direction, so it is returned unchanged instead of
raising an arithmetic error. Check the result with `magnitude/1` if your
caller needs to distinguish that case.

## Examples

    iex> AstroUtils.Vector.normalize({3.0, 4.0, 0.0})
    {0.6, 0.8, 0.0}

    iex> AstroUtils.Vector.normalize({0.0, 0.0, 0.0})
    {0.0, 0.0, 0.0}

# `scale`

```elixir
@spec scale(t(), number()) :: t()
```

Multiply every component by the scalar `s`.

## Examples

    iex> AstroUtils.Vector.scale({1.0, -2.0, 0.5}, 2.0)
    {2.0, -4.0, 1.0}

# `subtract`

```elixir
@spec subtract(t(), t()) :: t()
```

Component-wise difference `a - b`.

## Examples

    iex> AstroUtils.Vector.subtract({4.0, 5.0, 6.0}, {1.0, 2.0, 3.0})
    {3.0, 3.0, 3.0}

---

*Consult [api-reference.md](api-reference.md) for complete listing*
