
# tecs.math.vec2


Allocation-free two-dimensional vector and point math.

`vec2` takes separate coordinates and returns multiple values, so a system
can update an archetype column without allocating vector objects:

```teal
local record Homing is tecs.ecs.Component
    targetX: number
    targetY: number
    speed: number
end

tecs.ecs.newFFIComponent({
    name = "Homing",
    container = Homing,
    fields = {
        {"targetX", "float"},
        {"targetY", "float"},
        {"speed", "float"},
    },
})

return tecs.newApplication({
    plugin = function(world: tecs.World)
        local homing <const> = world:newQuery({
            include = {tecs.Transform2D, Homing},
        })

        world:addSystem({
            name = "game.Homing",
            phase = tecs.ecs.phases.Update,
            run = function(dt: number)
                for archetype, length in homing:iter() do
                    local transforms <const> = archetype:getMut(
                        tecs.Transform2D
                    )
                    local targets <const> = archetype:get(Homing)

                    for row = 1, length do
                        local transform <const> = transforms[row]
                        local target <const> = targets[row]

                        transform.x, transform.y = tecs.math.vec2.moveTowards(
                            transform.x,
                            transform.y,
                            target.targetX,
                            target.targetY,
                            target.speed * dt
                        )
                        transform.rotation = tecs.math.vec2.angle(
                            target.targetX - transform.x,
                            target.targetY - transform.y
                        )
                    end
                end
            end,
        })
    end,
})
```

The writable [`Transform2D`](/modules/ecs/#tecs.ecs.Transform2D) column comes from `getMut`; the read-only target
column comes from `get`. Taking both through `getMut` would dirty `Homing`
every frame and defeat consumers that skip clean columns.

## Coordinates and boundaries

Every angle uses radians. A positive quarter turn maps `(1, 0)` to `(0, 1)`,
which appears clockwise when screen y grows downward.

Operations without a unique geometric answer return stable values.
`normalize(0, 0)`, either angle-between function with a zero vector, and
`project` onto a zero axis return zero. `reflect` with a zero normal returns
the original vector. `lerp` does not clamp, and `moveTowards` never
overshoots.

## Module contents

### Functions

| Function | Kind | Description |
| --- | --- | --- |
| [`add`](/modules/math/vec2/#tecs.math.vec2.add) | <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span> | Adds two vectors. |
| [`angle`](/modules/math/vec2/#tecs.math.vec2.angle) | <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span> | Computes a vector's direction. |
| [`angleBetween`](/modules/math/vec2/#tecs.math.vec2.angleBetween) | <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span> | Computes the smaller unsigned angle between two vectors. |
| [`cross`](/modules/math/vec2/#tecs.math.vec2.cross) | <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span> | Computes the scalar two-dimensional cross product. |
| [`distance`](/modules/math/vec2/#tecs.math.vec2.distance) | <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span> | Computes the distance between two points. |
| [`distanceSquared`](/modules/math/vec2/#tecs.math.vec2.distanceSquared) | <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span> | Computes squared distance without taking a square root. |
| [`dot`](/modules/math/vec2/#tecs.math.vec2.dot) | <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span> | Computes the dot product of two vectors. |
| [`length`](/modules/math/vec2/#tecs.math.vec2.length) | <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span> | Computes vector length. |
| [`lengthSquared`](/modules/math/vec2/#tecs.math.vec2.lengthSquared) | <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span> | Computes squared vector length without taking a square root. |
| [`lerp`](/modules/math/vec2/#tecs.math.vec2.lerp) | <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span> | Interpolates linearly between two points. |
| [`moveTowards`](/modules/math/vec2/#tecs.math.vec2.moveTowards) | <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span> | Moves a point toward another by at most a given distance. |
| [`normalize`](/modules/math/vec2/#tecs.math.vec2.normalize) | <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span> | Produces a unit vector in the same direction. |
| [`project`](/modules/math/vec2/#tecs.math.vec2.project) | <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span> | Projects a vector onto another vector. |
| [`reflect`](/modules/math/vec2/#tecs.math.vec2.reflect) | <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span> | Reflects a vector across the line perpendicular to a normal. |
| [`rotate`](/modules/math/vec2/#tecs.math.vec2.rotate) | <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span> | Rotates a vector around the origin. |
| [`scale`](/modules/math/vec2/#tecs.math.vec2.scale) | <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span> | Multiplies both coordinates by a scalar. |
| [`signedAngleBetween`](/modules/math/vec2/#tecs.math.vec2.signedAngleBetween) | <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span> | Computes the smaller signed angle from one vector to another. |
| [`subtract`](/modules/math/vec2/#tecs.math.vec2.subtract) | <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span> | Subtracts the second vector from the first. |

## Functions

<a id="tecs.math.vec2.add"></a>
### tecs.math.vec2.add <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

Adds two vectors.



```teal
function tecs.math.vec2.add(
    ax: number, ay: number, bx: number, by: number
): number, number
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `ax` | `number` | First vector's x coordinate. |
| `ay` | `number` | First vector's y coordinate. |
| `bx` | `number` | Second vector's x coordinate. |
| `by` | `number` | Second vector's y coordinate. |

#### Returns

| Type | Description |
| --- | --- |
| `number` | The sum's x coordinate. |
| `number` | The sum's y coordinate. |

#### Examples


Combines a position with a per-frame velocity step.


```teal
local x, y = tecs.math.vec2.add(1, 2, 3, 4)

assert(x == 4 and y == 6)
```

<a id="tecs.math.vec2.angle"></a>
### tecs.math.vec2.angle <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

Computes a vector's direction.



```teal
function tecs.math.vec2.angle(x: number, y: number): number
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `x` | `number` | Vector's x coordinate. |
| `y` | `number` | Vector's y coordinate. |

#### Returns

| Type | Description |
| --- | --- |
| `number` | `atan2(y, x)` in `[-pi, pi]`. A zero vector returns zero. |

#### Examples


Converts a direction into a rotation for a sprite.


```teal
assert(tecs.math.vec2.angle(0, 1) == math.pi / 2)
```

<a id="tecs.math.vec2.angleBetween"></a>
### tecs.math.vec2.angleBetween <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

Computes the smaller unsigned angle between two vectors.



```teal
function tecs.math.vec2.angleBetween(
    ax: number, ay: number, bx: number, by: number
): number
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `ax` | `number` | First vector's x coordinate. |
| `ay` | `number` | First vector's y coordinate. |
| `bx` | `number` | Second vector's x coordinate. |
| `by` | `number` | Second vector's y coordinate. |

#### Returns

| Type | Description |
| --- | --- |
| `number` | Radians in `[0, pi]`. If either vector is zero, returns zero. |

#### Examples


Measures the unsigned separation of two facing directions.


```teal
assert(tecs.math.vec2.angleBetween(1, 0, 0, 1) == math.pi / 2)
```

<a id="tecs.math.vec2.cross"></a>
### tecs.math.vec2.cross <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

Computes the scalar two-dimensional cross product.



```teal
function tecs.math.vec2.cross(
    ax: number, ay: number, bx: number, by: number
): number
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `ax` | `number` | First vector's x coordinate. |
| `ay` | `number` | First vector's y coordinate. |
| `bx` | `number` | Second vector's x coordinate. |
| `by` | `number` | Second vector's y coordinate. |

#### Returns

| Type | Description |
| --- | --- |
| `number` | `ax * by - ay * bx`; positive puts the second vector on the positive rotation side of the first. |

#### Examples


Determines which side of a direction another vector lies on.


```teal
assert(tecs.math.vec2.cross(1, 0, 0, 1) == 1)
```

<a id="tecs.math.vec2.distance"></a>
### tecs.math.vec2.distance <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

Computes the distance between two points.



```teal
function tecs.math.vec2.distance(
    ax: number, ay: number, bx: number, by: number
): number
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `ax` | `number` | First point's x coordinate. |
| `ay` | `number` | First point's y coordinate. |
| `bx` | `number` | Second point's x coordinate. |
| `by` | `number` | Second point's y coordinate. |

#### Returns

| Type | Description |
| --- | --- |
| `number` | The nonnegative Euclidean distance between the points. |

#### Examples


Measures how far apart two positions are.


```teal
assert(tecs.math.vec2.distance(1, 2, 4, 6) == 5)
```

<a id="tecs.math.vec2.distanceSquared"></a>
### tecs.math.vec2.distanceSquared <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

Computes squared distance without taking a square root.

Prefer this to `distance` for radius tests.



```teal
function tecs.math.vec2.distanceSquared(
    ax: number, ay: number, bx: number, by: number
): number
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `ax` | `number` | First point's x coordinate. |
| `ay` | `number` | First point's y coordinate. |
| `bx` | `number` | Second point's x coordinate. |
| `by` | `number` | Second point's y coordinate. |

#### Returns

| Type | Description |
| --- | --- |
| `number` | The squared Euclidean distance between the points. |

#### Examples


Tests whether a target lies inside a radius without a square root.


```teal
assert(tecs.math.vec2.distanceSquared(1, 2, 4, 6) == 25)
```

<a id="tecs.math.vec2.dot"></a>
### tecs.math.vec2.dot <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

Computes the dot product of two vectors.



```teal
function tecs.math.vec2.dot(
    ax: number, ay: number, bx: number, by: number
): number
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `ax` | `number` | First vector's x coordinate. |
| `ay` | `number` | First vector's y coordinate. |
| `bx` | `number` | Second vector's x coordinate. |
| `by` | `number` | Second vector's y coordinate. |

#### Returns

| Type | Description |
| --- | --- |
| `number` | `ax * bx + ay * by`. |

#### Examples


Tests how closely two directions face each other.


```teal
assert(tecs.math.vec2.dot(2, 3, 4, 5) == 23)
```

<a id="tecs.math.vec2.length"></a>
### tecs.math.vec2.length <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

Computes vector length.



```teal
function tecs.math.vec2.length(x: number, y: number): number
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `x` | `number` | Vector's x coordinate. |
| `y` | `number` | Vector's y coordinate. |

#### Returns

| Type | Description |
| --- | --- |
| `number` | The nonnegative Euclidean length. |

#### Examples


Measures a velocity's speed.


```teal
assert(tecs.math.vec2.length(3, 4) == 5)
```

<a id="tecs.math.vec2.lengthSquared"></a>
### tecs.math.vec2.lengthSquared <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

Computes squared vector length without taking a square root.

Prefer this to `length` when comparing magnitudes: compare the answer
with the other distance squared, such as `radius * radius`.



```teal
function tecs.math.vec2.lengthSquared(x: number, y: number): number
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `x` | `number` | Vector's x coordinate. |
| `y` | `number` | Vector's y coordinate. |

#### Returns

| Type | Description |
| --- | --- |
| `number` | `x * x + y * y`. |

#### Examples


Compares speed without taking a square root.


```teal
assert(tecs.math.vec2.lengthSquared(3, 4) == 25)
```

<a id="tecs.math.vec2.lerp"></a>
### tecs.math.vec2.lerp <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

Interpolates linearly between two points.



```teal
function tecs.math.vec2.lerp(
    ax: number, ay: number, bx: number, by: number, t: number
): number, number
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `ax` | `number` | Starting point's x coordinate. |
| `ay` | `number` | Starting point's y coordinate. |
| `bx` | `number` | Destination point's x coordinate. |
| `by` | `number` | Destination point's y coordinate. |
| `t` | `number` | Unclamped interpolation amount. Zero returns the start, one returns the destination, and values outside that interval extrapolate. |

#### Returns

| Type | Description |
| --- | --- |
| `number` | The interpolated x coordinate. |
| `number` | The interpolated y coordinate. |

#### Examples


Blends halfway between two positions.


```teal
local x, y = tecs.math.vec2.lerp(2, 4, 6, 8, 0.5)

assert(x == 4 and y == 6)
```

<a id="tecs.math.vec2.moveTowards"></a>
### tecs.math.vec2.moveTowards <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

Moves a point toward another by at most a given distance.

A frame-rate-independent chase passes the speed for this frame:



```teal
function tecs.math.vec2.moveTowards(
    x: number,
    y: number,
    targetX: number,
    targetY: number,
    maxDistance: number
): number, number
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `x` | `number` | Starting point's x coordinate. |
| `y` | `number` | Starting point's y coordinate. |
| `targetX` | `number` | Destination point's x coordinate. |
| `targetY` | `number` | Destination point's y coordinate. |
| `maxDistance` | `number` | Greatest distance to travel. A nonpositive value leaves the starting point unchanged. |

#### Returns

| Type | Description |
| --- | --- |
| `number` | The moved x coordinate. Reaching the destination returns it exactly and never overshoots. |
| `number` | The moved y coordinate, with the same endpoint rule. |

#### Examples


Moves toward a target without overshooting it.


```teal
local x, y = tecs.math.vec2.moveTowards(0, 0, 3, 4, 2)

assert(x == 1.2 and y == 1.6)
```

<a id="tecs.math.vec2.normalize"></a>
### tecs.math.vec2.normalize <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

Produces a unit vector in the same direction.



```teal
function tecs.math.vec2.normalize(x: number, y: number): number, number
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `x` | `number` | Vector's x coordinate. |
| `y` | `number` | Vector's y coordinate. |

#### Returns

| Type | Description |
| --- | --- |
| `number` | The normalized x coordinate. A zero vector returns zero because it has no direction. |
| `number` | The normalized y coordinate, with the same zero-vector rule. |

#### Examples


Builds a unit direction toward a target.


```teal
local x, y = tecs.math.vec2.normalize(3, 4)

assert(x == 0.6 and y == 0.8)
```

<a id="tecs.math.vec2.project"></a>
### tecs.math.vec2.project <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

Projects a vector onto another vector.

The projection axis may have any length:



```teal
function tecs.math.vec2.project(
    x: number, y: number, ontoX: number, ontoY: number
): number, number
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `x` | `number` | The vector's x coordinate. |
| `y` | `number` | The vector's y coordinate. |
| `ontoX` | `number` | Projection axis's x coordinate. |
| `ontoY` | `number` | Projection axis's y coordinate. |

#### Returns

| Type | Description |
| --- | --- |
| `number` | The projected x coordinate. The axis may have any length; a zero axis returns zero. |
| `number` | The projected y coordinate, with the same zero-axis rule. |

#### Examples


Keeps only the component of a velocity along an axis.


```teal
local x, y = tecs.math.vec2.project(3, 4, 1, 0)

assert(x == 3 and y == 0)
```

<a id="tecs.math.vec2.reflect"></a>
### tecs.math.vec2.reflect <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

Reflects a vector across the line perpendicular to a normal.

The normal may have any length:



```teal
function tecs.math.vec2.reflect(
    x: number, y: number, normalX: number, normalY: number
): number, number
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `x` | `number` | The vector's x coordinate. |
| `y` | `number` | The vector's y coordinate. |
| `normalX` | `number` | Surface normal's x coordinate. |
| `normalY` | `number` | Surface normal's y coordinate. |

#### Returns

| Type | Description |
| --- | --- |
| `number` | The reflected x coordinate. The normal may have any length; a zero normal returns the original x coordinate. |
| `number` | The reflected y coordinate, with the same zero-normal rule. |

#### Examples


Bounces a velocity from a surface normal.


```teal
local x, y = tecs.math.vec2.reflect(1, -1, 0, 1)

assert(x == 1 and y == 1)
```

<a id="tecs.math.vec2.rotate"></a>
### tecs.math.vec2.rotate <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

Rotates a vector around the origin.



```teal
function tecs.math.vec2.rotate(
    x: number, y: number, radians: number
): number, number
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `x` | `number` | Vector's x coordinate. |
| `y` | `number` | Vector's y coordinate. |
| `radians` | `number` | Rotation in radians. A positive quarter turn maps `(1, 0)` to `(0, 1)`. |

#### Returns

| Type | Description |
| --- | --- |
| `number` | The rotated x coordinate. |
| `number` | The rotated y coordinate. |

#### Examples


Rotates a facing direction by a quarter turn.


```teal
local x, y = tecs.math.vec2.rotate(1, 0, math.pi / 2)

assert(math.abs(x) < 0.000001 and math.abs(y - 1) < 0.000001)
```

<a id="tecs.math.vec2.scale"></a>
### tecs.math.vec2.scale <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

Multiplies both coordinates by a scalar.



```teal
function tecs.math.vec2.scale(
    x: number, y: number, factor: number
): number, number
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `x` | `number` | Vector's x coordinate. |
| `y` | `number` | Vector's y coordinate. |
| `factor` | `number` | Multiplier applied to both coordinates. |

#### Returns

| Type | Description |
| --- | --- |
| `number` | The scaled x coordinate. |
| `number` | The scaled y coordinate. |

#### Examples


Turns a unit direction into a movement step.


```teal
local x, y = tecs.math.vec2.scale(2, 3, 4)

assert(x == 8 and y == 12)
```

<a id="tecs.math.vec2.signedAngleBetween"></a>
### tecs.math.vec2.signedAngleBetween <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

Computes the smaller signed angle from one vector to another.

Use the answer directly as the shortest directional correction:



```teal
function tecs.math.vec2.signedAngleBetween(
    ax: number, ay: number, bx: number, by: number
): number
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `ax` | `number` | Starting vector's x coordinate. |
| `ay` | `number` | Starting vector's y coordinate. |
| `bx` | `number` | Destination vector's x coordinate. |
| `by` | `number` | Destination vector's y coordinate. |

#### Returns

| Type | Description |
| --- | --- |
| `number` | Radians in `[-pi, pi)`, positive in the same sense as `rotate`. If either vector is zero, returns zero; an exact half-turn is negative pi. |

#### Examples


Chooses the shortest directional correction toward a target.


```teal
assert(tecs.math.vec2.signedAngleBetween(1, 0, 0, 1) == math.pi / 2)
```

<a id="tecs.math.vec2.subtract"></a>
### tecs.math.vec2.subtract <span class="tealdoc-kind-badge tealdoc-kind-static">Static</span>

Subtracts the second vector from the first.



```teal
function tecs.math.vec2.subtract(
    ax: number, ay: number, bx: number, by: number
): number, number
```

#### Arguments

| Name | Type | Description |
| --- | --- | --- |
| `ax` | `number` | First vector's x coordinate. |
| `ay` | `number` | First vector's y coordinate. |
| `bx` | `number` | Second vector's x coordinate. |
| `by` | `number` | Second vector's y coordinate. |

#### Returns

| Type | Description |
| --- | --- |
| `number` | The difference's x coordinate. |
| `number` | The difference's y coordinate. |


#### Examples


Finds the offset from a position to a target.


```teal
local x, y = tecs.math.vec2.subtract(5, 4, 1, 2)

assert(x == 4 and y == 2)
```