# Geometry Library

The Storm standard library provides a number of types for 2D and 3D geometry in its standard library. These are provided to make it easier for different graphics libraries to interact with each other, even if parts of them are implemented in C++.

All of these types and functions are in the `core.geometry` package. All their members treat the values as if they were immutable. That is, it is possible to modify the contents of all values except for `Angle` by assigning to their members. All member functions do, however, not modify the data structure, but instead return an updated copy. This typically makes it easier to chain operations conveniently without unintended side-effects.

## Point

The value `core.geometry.Point` stores a 2-dimensional point expressed by 2 `core.Float`s named `x` and `y`. The implementation assumes that points appear in a coordinate system where positive `x` is towards the right, and positive `y` is downwards (as is typical for 2D computer graphics).

The `Point` type has the expected arithmetic operations as overloaded operators. Namely, addition, subtraction, multiplication with a scalar, and division by a scalar. The `*` operator for two points is overloaded as the dot product. It also has the following members:

- `core.geometry.Point tangent()`

  Tangent. Always 90 deg clockwise from the vector in screen-space.

- `core.Float lengthSq()`

  Compute the length squared of the point. Cheaper than the length.

- `core.Float length()`

  Compute the lenght of the point.

- `core.Float taxiLength()`

  Compute the taxicab/manhattan length (i.e. x + y).

- `core.geometry.Point normalized()`

  Return a normalized point (i.e. length 1). If the point has length zero, then the original point is returned.

The following free functions are also available:

- `core.geometry.Point abs(core.geometry.Point a)`

  Compute the absolute value of both compontents in the point.

- `core.geometry.Point project(core.geometry.Point pt, core.geometry.Point origin, core.geometry.Point dir)`

  Project the point `pt` onto a line that starts in `origin` and expands in the direction of `dir`. `dir` does not have to be normalized.

## Size

The value `core.geometry.Size` stores a 2-dimensional size expressed by 2 `core.Float`s named `w` and `h` (for width and height). Since the `Size` class is expected to represent a size, both of `w` and `h` are expected to be non-negative.

Overall, the size is convertible to a `Point`, and follows the same basic interface. However, due to the expectation that it contains a size, the interface is smaller. Apart from arithmetic operators, it has the following members:

- `init()`

  Create a size of zero.

- `init(core.Float wh)`

  Create a size with width and height set to the same value.

- `init(core.Float w, core.Float h)`

  Create a size with separate width and height.

- `init(core.geometry.Point pt)`

  Create a size from a point.

- `core.Bool valid()`

  Check if the components are non-negative.

- `core.geometry.Size min(core.geometry.Size o)`

  Component-wise minimum of two sizes.

- `core.geometry.Size max(core.geometry.Size o)`

  Component-wise maximum of two sizes.

Apart from the members, the following free functions are available:

- `core.Float max(core.geometry.Size x)`

  Get the maximum of the two components.

- `core.Float min(core.geometry.Size x)`

  Get the minimum of the two components.

- `core.geometry.Size abs(core.geometry.Size a)`

  Normalize a size by taking its absolute value.

- `core.geometry.Point center(core.geometry.Size s)`

  Center point of a size.

## Rect

The value `core.geometry.Rect` stores a 2-dimensional rectangle, expressed as two points, `p0` and `p1`. The first point `p0` is the top-left corner of the rectangle, and `p1` is the bottom-right corner of the rectangle. The member functions of `Rect` considers the rectangle to contain all points from `p0` up to, but not including `p1`. The class also contains the function `size` that computes the size of the rectangle. The `size` function also has an assignment variant, so it is possible to treat the point as if it cointained a point `p0` for the top-left corner, and a `size` instead of two points.

The `Rect` type has overloads the `+` and `-` operators where the right hand side is a `Point` to translate a rectangle based on the coordinates in the point.

The `Rect` type has the following parameters:

- `init()`

  Create an empty rectangle.

- `init(core.geometry.Size s)`

  Initialize to (0, 0)-(size)

- `init(core.geometry.Point p, core.geometry.Size s)`

  Initialize to point and size.

- `init(core.geometry.Point topLeft, core.geometry.Point bottomRight)`

  Initialize to two points.

- `init(core.Float left, core.Float top, core.Float right, core.Float bottom)`

  Initialize to raw coordinates.

- `core.geometry.Rect normalized()`

  Return a normalized rectangle, where `p0` is to the top-left of `p1`.

- `core.Bool contains(core.geometry.Point pt)`

  Does this rectangle contain the point `pt`.

- `core.Bool contains(core.geometry.Rect rect)`

  Does this rectangle contain another rectangle? For this to be true, all parts of `rect` needs to be inside this rectangle.

- `core.Bool intersects(core.geometry.Rect other)`

  Does this rectangle intersect with another rectangle?

- `core.geometry.Rect sized(core.geometry.Size to)`

  Return a rectangle with the same origin, but the specified size.

- `core.geometry.Point center()`

  Compute the center of the rectangle.

- `core.geometry.Rect at(core.geometry.Point to)`

  Move the origin of the rectangle to `to`.

- `core.geometry.Rect include(core.geometry.Point to)`

  Increase the rectangle to include the point `to`. Can be seen as a single step in computing a bounding box of a number of points.

- `core.geometry.Rect include(core.geometry.Rect other)`

  Increase the dimensions of the rectangle to include `other`. Can be seen as the union of two bounding boxes.

- `core.geometry.Rect scaled(core.Float scale)`

  Scale the entire rect around its center.

- `core.geometry.Rect shrink(core.geometry.Size rate)`

  Shrink the rectangle in all dimensions based on the height and width in `rate`.

- `core.geometry.Rect grow(core.geometry.Size rate)`

  Grow the rectangle in all dimensions based on the height and width in `rate`.

The following free functions are also available:

- `core.Bool inside(core.geometry.Point pt, core.geometry.Rect r)`

  Check if the point `pt` is inside the rectangle `r`. Same as `r.contains(pt)`.

## Angle

The value `core.geometry.Angle` represents an angle in some unit (internally, radians is used, but this may change). The value overloads the operators `+` and `-` for adding and subtracting angles, and the operators `*` and `/` for multiplication and division by a scalar. While the `Angle` type does not contain any constructors, the functions `deg` and `rad` are provided instead. Furthermore, Basic Storm allows creating angles using units, like so:

    Angle a = 90 deg;
    Angle b = 2.3 rad;
    Float pi = (180 deg).rad();

An `Angle` is not limited to contain a value between 0 and 360 degrees. However, storing large angle values will yield a loss in precision. The member `normalized` normalizes the angle to between 0 and 360 degrees.

As mentioned above, the following functions are used to create angles from numbers in degrees or radians:

- `core.geometry.Angle deg(core.Float v)`
- `core.geometry.Angle rad(core.Float v)`

The `Angle` class contains the following members:

- `core.geometry.Angle normalized()`

  Return a normalized angle that lies between 0 and 360 degrees.

- `core.geometry.Angle opposite()`

  Return an angle in the opposite direction. Normalizes the result after the computation.

- `core.Float rad()`

  Convert to radians.

- `core.Float deg()`

  Convert to degrees.

There are also a number of free functions that utilize angles together with other parts of the geometry package:

- `core.Float sin(core.geometry.Angle v)`

  Compute the sin of an angle.

- `core.Float cos(core.geometry.Angle v)`

  Compute the cos of an angle.

- `core.Float tan(core.geometry.Angle v)`

  Compute the tan of an angle.

- `core.geometry.Angle asin(core.Float v)`

  Compute asin of a float.

- `core.geometry.Angle acos(core.Float v)`

  Compute acos of a float.

- `core.geometry.Angle atan(core.Float v)`

  Compute atan of a float.

- `core.geometry.Angle angle(core.geometry.Point pt)`

  Compute the angle of the point. Zero degrees is the point (0, -1), i.e. downwards in screen space.

- `core.geometry.Point angle(core.geometry.Angle angle)`

  Create an angle based on the point. 0 deg is (0, -1)

## Vector

The library also provides a type for 3-dimensional coordinates. This type is name `core.geometry.Vector`. As with points, the type provides arithmetic operations for vector addition, subtraction, and multiplication with scalars. It is also possible to implicitly cast a `Point` into a `Vector` in order to make it easier to use transforms for both 2D and 3D coordinates.

The 3-dimensional `Vector` uses `*` for dot product, and `/` for cross product.

Apart from that, the interface is similar to that of `Point`, but some operations are missing due to them having a different meaning in 3 dimensions:

- `core.Float lengthSq()`

  Compute the length squared of the vector. Cheaper to compute than the length.

- `core.Float length()`

  Compute the length of the vector.

- `core.Float taxiLength()`

  Compute the taxicab/manhattan length (i.e. x + y + z).

- `core.geometry.Vector normalized()`

  Return a normalized vector (i.e. length 1).

Similarly, there are also a few free functions:

- `core.geometry.Vector abs(core.geometry.Vector a)`

  Compute the absolute value of both compontents in the point.

- `core.geometry.Vector project(core.geometry.Vector pt, core.geometry.Vector origin, core.geometry.Vector dir)`

  Project the point `pt` onto a line that starts in `origin` and expands in the direction of `dir`. `dir` does not have to be normalized.

## Transform

The library also contains the `core.geometry.Transform` class, which represents a 3-dimensional affine transform using a 4 by 4 matrix. This means that the transform can represent arbitrary combinations of for example translation, rotation, scaling, skewing, and projections.

A transform interprets points or vectors as four-dimensional row-vectors. The fourth element, `w`, is set to 1 for the purposes of the transform. The row vector is multiplied with the transform matrix from the left, and the resulting four-dimensional vector is reduced to three dimensions by dividing the `x`, `y`, and `z` coordinates by `w`. As such, when transforms are multiplied together as `a * b * c`, then they will be applied from left to right with respect to the geometry.

The `transform` class itself has few members:

- `init()`

  Unit transform.

- `core.geometry.Transform *(core.geometry.Transform o)`

  Multiply two transforms, creates a transform that performs both original transforms in sequence.

- `core.geometry.Transform inverted()`

  Invert the transform.

- `core.Float at(core.Nat row, core.Nat col)`

  Get a single element.

There are, however, a number of free functions that allow transforming points and vectors:

- `core.geometry.Vector *(core.geometry.Vector o, core.geometry.Transform tfm)`

  Transform a vector using a transform.

- `core.geometry.Point *(core.geometry.Point o, core.geometry.Transform tfm)`

  Transform a point using a transform.

There are also a number of functions that create various transforms:

- `core.geometry.Transform translate(core.geometry.Vector v)`

  Creates a transform that translates points by the coordinate `v`. Also accepts `v` as a `Point` or a `Size`.

- `core.geometry.Transform rotateX(core.geometry.Angle angle)`

  Creates a transform that rotates points around the X axis. Also available for the Y axis and the Z axis.

- `core.geometry.Transform rotateX(core.geometry.Angle angle, core.geometry.Vector origin)`

  Creates a transform that rotates point around a line that extends from the point `origin` and is parallel to the X axis. As with the other rotate function, there are variants for the Y axis and the Z axis as well.

- `core.geometry.Transform rotate(core.geometry.Angle angle)`

  Creates a transform that rotates points around the Z axis. This is the one rotation that is relevant in 2 dimensions, which is why it has a special name.

- `core.geometry.Transform rotate(core.geometry.Angle angle, core.geometry.Point origin)`

  Creates a transform that rotates points around a line that extends from `origin` that is parallel to the the Z axis. This is the one rotation that is relevant in 2 dimensions, which is why it has a special name.

- `core.geometry.Transform scale(core.geometry.Vector scale)`

  Creates a transform that scales points according to the dimensions in `scale`. Also available in versions that accepts `scale` as a `Float` (affects all axes), and a `Size` (affects the X and Y axes).

- `core.geometry.Transform skewX(core.geometry.Angle angle)`

  Creates a transform that skews points along the X axis by `angle`. Also available in versions that skew along the Y axis and the Z axis.