# `Quiddity.Camera`
[🔗](https://github.com/d-led/ex.quiddity/blob/main/lib/quiddity/camera.ex#L1)

A pinhole camera: where a sensor is, what it looks along, and how wide it sees.

The basis is spelled out rather than inferred — `forward`, `right`, `up` — so a
frame's pixel geometry is a property of this struct and nothing has to agree
with MuJoCo about which way a camera's own −z points. The defaults are a patch
sensor's: 64 × 64 pixels over a 66° field of view, a metre past the part, so a
frame rendered here and a frame rendered by a simulator can cover the same
solid angle.

Millimetres, everywhere: a STEP file is in millimetres and so is this.

# `t`

```elixir
@type t() :: %Quiddity.Camera{
  far: float(),
  forward: [float()],
  fov_x: float(),
  height: pos_integer(),
  near: float(),
  origin: [float()],
  right: [float()],
  up: [float()],
  width: pos_integer()
}
```

# `cam_to_world`

```elixir
@spec cam_to_world(t()) :: [[float()]]
```

The camera's basis and origin as a 4 × 4 matrix, rows first.

# `least_aligned_axis`

```elixir
@spec least_aligned_axis([float()]) :: [float()]
```

The world axis least aligned with a direction — a usable roll reference.

# `looking_at`

```elixir
@spec looking_at([float()], [float()], keyword()) ::
  {:ok, t()} | {:error, Quiddity.Error.t()}
```

A camera at *eye* looking at *target*.

Options: `:width`, `:height`, `:fov_x` (radians), `:up` (the roll reference,
defaulting to the world axis least aligned with the view so a straight-down
look still has a sensible up), `:near` and `:far`.

# `patch`

```elixir
@spec patch([float()], [float()], keyword()) ::
  {:ok, t()} | {:error, Quiddity.Error.t()}
```

A sensor placed *distance* mm off a surface, looking straight at it.

This is the placement a patch camera has on a part: the eye sits on the outward
normal, the view runs back down it. The roll reference is a tangent to the
surface, so the patch's rows and columns follow the surface rather than the
world.

# `pixel_size`

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

The width one pixel covers at *distance* mm, in millimetres.

# `tangent`

```elixir
@spec tangent([float()]) :: [float()]
```

A tangent to a surface with *normal*: the direction a patch's `up` follows.

The world axis least aligned with the normal is crossed with it, so a part
that is not aligned to the world gets a tangent that follows it, and a part
that is gets one along its own axes.

# `to_params`

```elixir
@spec to_params(t()) :: map()
```

The camera as the engine reads it.

---

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