# Vector

Representation of 3D vectors and points.

This structure is used to pass 3D positions and directions around. It also contains functions for doing common vector operations.

Besides the functions listed below, other classes can be used to manipulate vectors and points as well.

Example Usage: `target = Vector(1, 0, 0) + Vector(0, 2, 0):normalized()`

Check Manipulation examples for more detailed usage.

Tip

Vector and Color are the first classes to be defined in pure Lua. This means you have to use colon operator (e.g. `pos:angle()`) to call member functions, not the dot operator. Failing to do so will fail with cryptic error messages displayed.

## Constructors summary¶

Tip

Every place that returns a coordinate table, like `obj.getPosition()`, serves a Vector class instance already - you do not have to explicitly construct it. When constructing Vector instances, the `.new` part can be omitted, making e.g. `Vector(1, 2, 3)` equivalent to `Vector.new(1, 2, 3)`.

Function Name Description Return
Vector( x, y, z) Return a vector with specified (x, y, z) components.
Vector( v) Return a vector with x/y/z or 1/2/3 components from source table (x/y/z first).
Vector.new(...) Same as Vector(...).
Vector.min( vec1, vec2) Returns a vector that is made from the smallest components of two vectors.
Vector.max( vec1, vec2) Returns a vector that is made from the largest components of two vectors.
Vector.between( vec1, vec2) Return a vector pointing from vec1 to vec2.

### Constructors examples¶

``````function onLoad()
local vec1 = Vector.new(0.5, 1, 1.5)
local vec2 = Vector(1, -1, 0) -- same as Vector.new(1, -1, 0)

print(Vector.between(vec1, vec2)) --> Vector: {0.5, -2, -1.5}
print(Vector.max(vec1, vec2)) --> Vector: {1, 1, 1.5}
print(Vector.min(vec1, vec2)) --> Vector: {0.5, -1, -0}
end
``````

## Element access summary¶

In addition to accessing vector components by their numeric indices (1, 2, 3) and textual identifiers (x, y, z), the following methods may also be utilized.

Function Name Description Return
setAt( k, value) Sets a component to value and returns self.
set( x, y, z) Sets `x`, `y`, `z` components to given values and returns self.
get() Returns `x`, `y`, `z` components as three separate values.

copy() Returns a separate Vector with identical component values.

Tip

Before `Vector` was introduced, coordinate tables contained separate values under 1, 2, 3 and x, y, z keys, with letter keys taking precedence when they were different. This is no longer the case, and using letter and numerical keys is equivalent. However, when iterating over Vector components you have to use `pairs` and only letter keys will be read there.

### Element access examples¶

``````function onLoad()
local vec = Vector(1, 2, 3)
vec.x = 2 -- set the first component
vec = 4 -- set the second component
vec:setAt('z', 6) -- set the third component

print(vec:get()) --> same as print(vec.x, vec.y, vec.z)

for axis, value in pairs(vec) do
print(axis .. "="..value) --> x=2 then y=4 and finally z=6
end

vec:copy():setAt('x', - 11)
print(vec.x) --> 2, because we only changed 'x' on a copy
end
``````

## Arithmetics summary¶

Vector also allows you to use arithmetic operators to performs basic operations:

Operator Description Return
one + two Returns a new Vector that is a sum of `one` and `two`
one - two Returns a new Vector that is a difference of `one` and `two`
one * factor Returns a new Vector that is `one` with each component multiplied by the factor.
one == two Returns a boolean whether `one` and `two` are very similar to each other (less than ~0.03 difference in magnitude)

### Arithmetics examples¶

``````function onLoad()
local vec = Vector(1, 2, 3)
vec:add(Vector(3, 2, 1)) --> vec is now {4, 4, 4}
vec:sub(Vector(1, 0, 1)) --> vec is now {3, 4, 3}

local another = vec + Vector(-1, -2, -1) --> another is {2, 2, 2}, vec remains unchanged

print(another:equals(Vector(1, 2, 3))) --> false
print(another == Vector(2, 2, 2)) --> true
print(another == Vector(1.99, 2.01, 2)) --> true, small differences are tolerated
end
``````

## Methods summary¶

Tip

Numerous methods of Vector will return the instance to allow easy "chaining". That way you can do more complex processing without saving an intermediate result in a variable, like e.g. `vec:setAt('y', 0):scale(0.5):rotateOver('y', 90)`.

### Methods modifying self¶

Method Name Description Return
vec:sub( otherVec) Subtracts components of otherVec from self.
vec:scale( otherVec) Multiplies self-components by corresponding components from otherVec.
vec:scale( num) Multiplies self-components by a numeric factor.
vec:clamp( num) If self-magnitude is higher than provided limit, scale self-down to match it.
vec:normalize() Makes self-have a magnitude of 1.
vec:project( otherVec) Make self into projection on another vector.
vec:projectOnPlane( otherVec) Project self on a plane defined through a normal vector arg.
vec:reflect( otherVec) Reflect self over a plane defined through a normal vector arg.
vec:inverse() Multiply self-components by -1.
vec:moveTowards( otherVec, num) Move self towards another vector, but only up to a provided distance limit.
vec:rotateTowards( target, maxAngle) Rotate self towards another vector, but only up to a provided angle limit.
vec:rotateTowardsUnit( target, maxAngle) Same as rotateTowards, but only works correctly if `target` Vector is normalized. Less expensive than `rotateTowards`.
vec:rotateOver( axis, angle) Rotate a Vector `angle` degrees over given `axis` (can be `'x'`, `'y'`, `'z'`).

### Methods not modifying self¶

Method Name Description Return
vec1:dot( vec2) Return a dot product of two vectors.
vec:magnitude() Returns the length of this vector.
vec:sqrMagnitude() Returns the squared length of this vector.
p1:distance( p2) Returns distance between two points.
p1:sqrDistance( p2) Returns squared distance between two points.
vec1:equals( vec2, margin) Returns true if two vectors are approximately equal. The `margin` argument is optional and defaults to tolerating a difference of ~0.03 in both vector magnitude.
vec:string( prefix) Return string describing self, optional string prefix.
vec1:angle( vec2) Return an angle between two vectors, in degrees [0, 180].
vec1:cross( vec2) Return a cross-product vector of two vectors.
p1:lerp( p2, t) Linearly interpolates between two points. Numeric arg [0, 1] is the fraction.
vec:normalized() Return a new vector that is normalized (length 1) version of self.
vec:orthoNormalize() Return three normalized vectors perpendicular to each other, first one being in the same dir as self. Return `base`, `normal`, `binormal` vectors.

vec:orthoNormalize( binormalPlanar) Same as vec:orthoNormalize(), but second vector is guranteed to be on a self-binormalPlanar plane.

vec:heading() Returns an angle (In degrees) of rotation of Vector over all axis (`'x'`, `'y'`, `'z'`).

vec:heading( axis) Returns an angle (In degrees) of rotation of Vector over a given `axis` (can be `'x'`, `'y'`, `'z'`).

## Constructors details¶

### Vector.min(...)¶

Returns a vector that is made from the smallest components of two vectors.

Vector.min(vec1, vec2)

• vec1: First vector.
• vec2: Second vector.
``````vec1 = Vector(1, 2, 3)
vec2 = Vector(4, 3, 2)
print(Vector.min(vec1, vec2)) --> Vector: { 1, 2, 2 }
``````

### Vector.max(...)¶

Returns a vector that is made from the largest components of two vectors.

Vector.max(vec1, vec2)

• vec1: First vector.
• vec2: Second vector.
``````vec1 = Vector(1, 2, 3)
vec2 = Vector(4, 3, 2)
print(Vector.max(vec1, vec2)) --> Vector: { 4, 3, 3 }
``````

### Vector.between(...)¶

Return a vector pointing from vec1 to vec2.

Vector.between(vec1, vec2)

• vec1: First vector.
• vec2: Second vector.
``````vec1 = Vector(1, 2, 3)
vec2 = Vector(4, 3, 2)
print(Vector.between(vec1, vec2)) --> Vector: { 3, 1, -1 }
``````

## Element access details¶

### setAt(...)¶

Update one component of the vector and returning self.

setAt(key, num)

• key: Index of component (1, 2 or 3 for x, y or z).
• num: New value.
``````vec = Vector(1, 2, 3)
vec:setAt(1, 4):setAt('y', 3)
print(vec) --> Vector: { 4, 3, 3 }
``````

### set(...)¶

Update all components of the vector and returning self.

Providing a nil value makes it ignore that argument.

set(x, y, z)

• x: New value of X component.
• y: New value of Y component.
• z: New value of Z component.
``````vec = Vector(1, 2, 3)
vec:set(4, 3, 2)
print(vec) --> Vector: { 4, 3, 2 }
``````

### get()¶

Returns `x`, `y`, `z` components as three separate values.

``````vec = Vector(1, 2, 3)
x, y, z = vec:get()
print(x + y + z) --> 6
``````

### copy()¶

Copy self into a new vector and return it.

``````vec1 = Vector(1, 2, 3)
vec2 = vec1:copy()
vec1:set(4, 3, 2)
print(vec1) --> Vector { 4, 3, 2 }
print(vec2) --> Vector { 1, 2, 3 }
``````

## Methods details¶

### Methods modifying self details¶

Adds components of otherVec to self and returning self.

• otherVec: The vector to add.
``````vec = Vector(1, 2, 3)
otherVec = Vector(4, 5, 6)
print(vec) --> Vector: { 5, 7, 9 }

-- Same as
vec = Vector(1, 2, 3)
otherVec = Vector(4, 5, 6)
vec = vec + otherVec
print(vec) --> Vector: { 5, 7, 9 }
``````

#### sub(...)¶

Subtracts components of otherVec from self and returning self.

sub(otherVec)

• otherVec: The vector to subtracts.
``````vec = Vector(1, 2, 3)
otherVec = Vector(6, 5, 4)
vec:sub(otherVec)
print(vec) --> Vector: { -5, -3, -1 }

-- Same as
vec = Vector(1, 2, 3)
otherVec = Vector(6, 5, 4)
vec = vec - otherVec
print(vec) --> Vector: { -5, -3, -1 }
``````

#### scale(...)¶

Multiplies self-components by corresponding components from otherVec and returning self.

Every component in the result is a component of vec multiplied by the same component of otherVec or by a number factor.

scale(otherVec)

• otherVec: The vector to scale.

scale(num)

• num: The numeric factor.
``````vec = Vector(1, 2, 3)
otherVec = Vector(2, 3, 4)
vec:scale(otherVec)
print(vec) --> Vector: { 2, 6, 12 }
vec:scale(2)
print(vec) --> Vector: { 4, 12, 24 }
``````

#### clamp(...)¶

If self-magnitude is higher than provided limit, scale self-down to match it and returning self.

clamp(num)

• num: The numeric max magnitude.
``````vec = Vector(1, 2, 3)
vec:clamp(2)
print(vec) --> Vector: { 0.53, 1.07, 1.60 }
``````

#### normalize()¶

Makes this vector have a magnitude of 1 and returning self.

When normalized, a vector keeps the same direction but its length is 1.0.

Note that this function will change the current vector. If you want to keep the current vector unchanged, use normalized() method.

``````vec = Vector(1, 2, 3)
vec:normalize()
print(vec) --> Vector: { 0.27, 0.53, 0.80 }
``````

#### project(...)¶

Make self into projection on another vector and return self.

To understand vector projection, imagine that `otherVec` is resting on a line pointing in its direction. Somewhere along that line will be the nearest point to the tip of vector. The projection is just `otherVec` rescaled so that it reaches that point on the line.

project(otherVec)

• otherVec: The normal vector.
``````vec = Vector(2, 1, 4)
vec:project(Vector(1, - 2, 1))
print(vec) --> Vector: { 0.67, -1.3, 0.67 }
``````

#### projectOnPlane(...)¶

Projects a vector onto a plane defined by a normal orthogonal to the plane and return self.

A Vector stores the position of the given `vec` in 3d space. A second Vector is given by `otherVec` and defines a direction from a plane towards vector that passes through the origin. Vector.projectOnPlane uses the two Vector values to generate the position of vector in the `otherVec` direction, and return the location of the Vector on the plane.

projectOnPlane(otherVec)

• otherVec: The plane normal vector.
``````vec = Vector(2, 1, 4)
vec:projectOnPlane(Vector(1, - 2, 1))
print(vec) --> Vector: { 1.33, 2.33, 3.33 }
``````

#### reflect(...)¶

Make self into reflection on another vector and return self.

The `otherVec` vector defines a plane (a plane's normal is the vector that is perpendicular to its surface). The `vec` vector is treated as a directional arrow coming in to the plane. The returned value is a vector of equal magnitude to `vec` but with its direction reflected.

reflect(otherVec)

• otherVec: The normal vector.
``````vec = Vector(1, 2, 3)
vec:reflect(Vector(4, 3, 2))
print(vec) --> Vector: { -3.41, -1.31, 0.79 }
``````

#### inverse()¶

Multiply self-components by -1.

``````vec = Vector(1, 2, 3)
vec:inverse()
print(vec) --> Vector: { -1, -2, -3 }
``````

#### moveTowards(...)¶

Move self towards another vector, but only up to a provided distance limit and return self.

moveTowards(otherVec, num)

• target: The position to move towards.
• num: The distance limit.
``````vec = Vector(1, 2, 3)
vec:moveTowards(Vector(4, 3, 2), 0.5)
print(vec) --> Vector: { 1.45, 2.15, 2.85 }
``````

#### rotateTowards(...)¶

Rotate self towards another vector, but only up to a provided angle limit and return self.

This function is similar to moveTowards() except that the vector is treated as a direction rather than a position. The current vector will be rotated round toward the target direction by an angle of `maxAngle`, although it will land exactly on the target rather than overshoot. If the magnitudes of current and target are different, then the magnitude of the result will be linearly interpolated during the rotation. If a negative value is used for `maxAngle`, the vector will rotate away from target until it is pointing in exactly the opposite direction, then stops.

rotateTowards(target, maxAngle)

• target: The position to rotate towards.
• maxAngle: The maximum angle in degree allowed for this rotation.
``````vec = Vector(1, 2, 3)
vec:rotateTowards(Vector(4, 3, 2), 45)
print(vec) --> Vector: { 2.78, 2.08, 1.39 }
``````

#### rotateTowardsUnit(...)¶

Same as rotateTowards(), but only works correctly if `target` Vector is normalized and return self. Less expensive than `rotateTowards()`.

rotateTowardsUnit(target, maxAngle)

• target: The position to rotate towards.
• maxAngle: The maximum angle in degree allowed for this rotation.
``````vec = Vector(1, 2, 3)
vec:rotateTowardsUnit(Vector(4, 3, 2):normalized(), 45)
print(vec) --> Vector: { 3.29, 0.87, -1.55 }
``````

#### rotateOver(...)¶

Rotate a Vector `angle` degrees over given `axis` (can be `'x'`, `'y'`, `'z'`) and return self.

rotateOver(axis, angle)

• axis: The axis to rotate around.
• angle: The angle in degree for this rotation.
``````vec = Vector(3, 2, 3)
vec:rotateOver('y', 45)
print(vec) --> Vector: { 4.24, 2, 0 }
``````

### Methods not modifying self details¶

#### dot(...)¶

Return the dot product of two vectors.

The dot product is a float value equal to the magnitudes of the two vectors multiplied together and then multiplied by the cosine of the angle between them.

For normalized vectors Dot returns 1 if they point in exactly the same direction, -1 if they point in completely opposite directions and zero if the vectors are perpendicular.

vec1:dot(vec2)

• vec1: First vector.
• vec2: Second vector.
``````vec1 = Vector(0, 1, 2)
vec2 = Vector(0, 2, 4)
print(vec1:dot(vec2)) --> 10
print(Vector.dot(vec1:normalized(), vec2:normalized())) --> 1
``````

#### magnitude()¶

Returns the length of this vector.

``````vec = Vector(1, 2, 3)
print(vec:magnitude()) --> 3.74 (sqrt of 14)
print(Vector.magnitude(vec)) --> 3.74 (sqrt of 14)
``````

#### sqrMagnitude()¶

Returns the squared length of this vector.

``````vec = Vector(1, 2, 3)
print(vec:sqrMagnitude()) --> 14
print(Vector.sqrMagnitude(vec)) --> 14
``````

#### distance(...)¶

Returns distance between two points.

p1:distance(p2)

• p1: First point.
• p2: Second point.
``````p1 = Vector(1, 2, 3)
p2 = Vector(4, 3, 2)
print(p1:distance(p2)) --> 3.32
print(Vector.distance(p1, p2)) --> 3.32
print((p1 - p2):magnitude())  --> 3.32
``````

#### sqrDistance(...)¶

Returns squared distance between two points.

p1:sqrDistance(p2)

• p1: First point.
• p2: Second point.
``````p1 = Vector(1, 2, 3)
p2 = Vector(4, 3, 2)
print(p1:sqrDistance(p2)) --> 11
print(Vector.sqrDistance(p1, p2)) --> 11
``````

#### equals(...)¶

Returns true if two vectors are approximately equal. The `margin` argument is optional and defaults to tolerating a difference of `~0.03` in both vector magnitude.

vec1:equals(vec2, margin)

• vec1: First vector.
• vec2: Second vector.
• margin: (Optional) Numeric tolerance.
``````vec1 = Vector(1, 2, 3.10)
vec2 = Vector(1, 2, 3.15)
print(vec1:equals(vec2)) --> false
print(Vector.equals(vec1, vec2, 0.01)) --> true
``````

#### string(...)¶

Return string describing self, optional string prefix.

string(prefix)

• prefix: The prefix of return string.
``````vec = Vector(1, 2, 3)
str = vec:string('Prefix')
print(str) --> Prefix: { 1, 2, 3 }
print(vec:string('Prefix')) --> Prefix: { 1, 2, 3 }0
print(Vector.string(vec, 'Prefix')) --> Prefix: { 1, 2, 3 }0
``````

Warning

This function returns one extra float that will be displayed in print function. This value is returned by the last gsub used in internal function.

#### angle(...)¶

Returns the angle in degrees between two vectors.

The angle returned is the unsigned angle between the two vectors. This means the smaller of the two possible angles between the two vectors is used. The result is never greater than 180 degrees.

vec1:angle(vec2)

• vec1: First vector.
• vec2: Second vector.
``````vec1 = Vector(1, 2, 3)
vec2 = Vector(4, 3, 2)
print(vec1:angle(vec2)) --> 37.43
print(Vector.angle(vec1, vec2)) --> 37.43
``````

#### cross(...)¶

Return a cross-product vector of two vectors.

The cross product of two vectors results in a third vector which is perpendicular to the two input vectors. The result's magnitude is equal to the magnitudes of the two inputs multiplied together and then multiplied by the sine of the angle between the inputs. You can determine the direction of the result vector using the "left hand rule".

vec1:cross(vec2)

• vec1: First vector.
• vec2: Second vector.
``````vec1 = Vector(1, 2, 3)
vec2 = Vector(4, 3, 2)
print(vec1:cross(vec2)) --> Vector: { -5, 10, -5 }
print(vec2:cross(vec1)) --> Vector: { -5, -10, 5 }
print(Vector.cross(vec1, vec2)) --> Vector: { -5, 10, -5 }
print(Vector.cross(vec2, vec1)) --> Vector: { -5, -10, 5 }
``````

#### lerp(...)¶

Linearly interpolates between two points.

Interpolates between the points a and b by the interpolant t. The parameter t is clamped to the range [0, 1]. This is most commonly used to find a point some fraction of the way along a line between two endpoints (e.g. to move an object gradually between those points).

The value returned equals (b - a) * t. When t = 0 returns a. When t = 1 returns b. When t = 0.5 returns the point midway between a and b.

p1:lerp(p2, t)

• p1: First point.
• p2: Second point.
• t: Fraction.
``````p1 = Vector(1, 2, - 4)
p2 = Vector(1, 2, 4)
print(p1:lerp(p2, 0.25)) --> Vector: { 1, 2, -2 }
print(Vector.lerp(p1, p2, 0.25)) --> Vector: { 1, 2, -2 }
``````

#### normalized()¶

Return a new vector that is normalized (length 1) version of self.

``````vec = Vector(1, 2, 3)
print(vec:normalized()) --> Vector: { 0.27, 0.53, 0.80}
print(Vector.normalized(vec)) --> Vector: { 0.27, 0.53, 0.80}
``````

#### orthoNormalize(...)¶

Return three normalized vectors perpendicular to each other, first one being in the same direction as self. If `binormalPlaner` is provided, the second vector is guaranteed to be on a self-binormalPlanar plane.

orthoNormalize(binormalPlanar)

• binormalPlanar: (optional) The vector for binormal planar.
``````vec = Vector(0, 0, 2)
base, normal, binormal = vec:orthoNormalize(Vector(0, 1, 0))
print(base) --> Vector: { 0, 0, 1}
print(normal) --> Vector: { -1, 0, 0}
print(binormal) --> Vector: { 0, -1, 0}
``````

Returns an angle (In degrees) of rotation of Vector over a given `axis` (can be `'x'`, `'y'`, `'z'`).

• axis: Can be `'x'`, `'y'`, `'z'`.
``````vec = Vector(1, 2, 3)
print(angle) --> 26.57
``````

## Manipulation examples¶

Moving an object towards a target position in small steps

``````function onLoad()
obj.lock()

local current =  Vector(10, 5, 0) -- obj starting position
local target =   Vector(-10, 5, 0) -- obj destination
local movementType = 'linear' -- try with 'spherical' or 'asymptotic' to see how other methods work

-- We want out movement stretched over time, a Wait will do it periodically
local waitID
waitID = Wait.time(
function()
-- move the current postion towards destination

if movementType == 'linear' then
-- simple linear movement, 1 unit at a time
current:moveTowards(target, 1)
elseif movementType == 'spherical' then
-- rotate towards target, 10 degress at a time
current:rotateTowards(target, 5)
elseif movementType == 'asymptotic' then
-- move quarter of the way towards target (take note that lerp does not modify current directly)
current = current:lerp(target, 0.25)
end

obj.setPositionSmooth(current, true, true)

-- if we reached the destination, stop this timer
if current == target then
Wait.stop(waitID)