Packages

Elixir library for transforming 3D homogeneous coordinates

Current section

Files

Jump to
transformations lib transformations.ex
Raw

lib/transformations.ex

defmodule Transformations do
@moduledoc """
Transformations is an Elixir library for translating, rotating, reflecting, scaling, shearing, projecting, orthogonalizing, and superimposing arrays of 3D homogeneous coordinates as well as for converting between rotation matrices, Euler angles, and quaternions. Also includes an Arcball control object and functions to decompose transformation matrices.
"""
@doc """
Create a new matrix.
## Examples
```elixir
iex(1)> point = Transformations.matrix([[1],[1],[1],[1]])
#Matrex[4×1]
┌ ┐
│ 1.0 │
│ 1.0 │
│ 1.0 │
│ 1.0 │
└ ┘
```
"""
def matrix(mtx) do
Matrex.new(mtx)
end
@doc """
Scale a shape by xs, ys and zs along the x, y and z axes.
## Examples
```elixir
iex(1)> shape = Transformations.matrix([
[0,1,1,0,0,1,1,0],
[0,0,0,0,1,1,1,1],
[0,0,1,1,0,0,1,1],
[1,1,1,1,1,1,1,1]
])
shape |> Transformations.scale(1,2,3)
#Matrex[4×8]
┌ ┐
│ 0.0 1.0 1.0 0.0 0.0 1.0 1.0 0.0 │
│ 0.0 0.0 0.0 0.0 2.0 2.0 2.0 2.0 │
│ 0.0 0.0 3.0 3.0 0.0 0.0 3.0 3.0 │
│ 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 │
└ ┘
```
"""
def scale(mtx, xs, ys, zs) do
s = Matrex.new([
[xs,0,0,0],
[0,ys,0,0],
[0,0,zs,0],
[0,0,0,1],
])
Matrex.dot(s, mtx)
end
@doc """
Transition (shift) a shape by xt, yt and zt along the x, y and z axes.
## Examples
```elixir
iex(1)> shape = Transformations.matrix([
[0,1,1,0,0,1,1,0],
[0,0,0,0,1,1,1,1],
[0,0,1,1,0,0,1,1],
[1,1,1,1,1,1,1,1]
])
shape |> Transformations.transition(1,2,3)
#Matrex[4×8]
┌ ┐
│ 1.0 2.0 2.0 1.0 1.0 2.0 2.0 1.0 │
│ 2.0 2.0 2.0 2.0 3.0 3.0 3.0 3.0 │
│ 3.0 3.0 4.0 4.0 3.0 3.0 4.0 4.0 │
│ 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 │
└ ┘
```
"""
def transition(mtx, xt, yt, zt) do
t = Matrex.new([
[1,0,0,xt],
[0,1,0,yt],
[0,0,1,zt],
[0,0,0,1],
])
Matrex.dot(t, mtx)
end
@doc """
Rotate a shape by angle about the x axis.
## Examples
```elixir
iex(1)> shape = Transformations.matrix([
[0,1,1,0,0,1,1,0],
[0,0,0,0,1,1,1,1],
[0,0,1,1,0,0,1,1],
[1,1,1,1,1,1,1,1]
])
shape |> Transformations.rotatex(45)
#Matrex[4×8]
┌ ┐
│ 0.0 1.0 1.0 0.0 0.0 1.0 1.0 0.0 │
│ 0.0 0.0 -0.8509 -0.8509 0.52532 0.52532-0.32558-0.32558 │
│ 0.0 0.0 0.52532 0.52532 0.8509 0.8509 1.37623 1.37623 │
│ 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 │
└ ┘
```
"""
def rotatex(mtx, angle) do
rx = Matrex.new([
[1,0,0,0],
[0,:math.cos(angle),-:math.sin(angle),0],
[0,:math.sin(angle), :math.cos(angle),0],
[0,0,0,1],
])
Matrex.dot(rx, mtx)
end
@doc """
Rotate a shape by angle about the y axis.
## Examples
```elixir
iex(1)> shape = Transformations.matrix([
[0,1,1,0,0,1,1,0],
[0,0,0,0,1,1,1,1],
[0,0,1,1,0,0,1,1],
[1,1,1,1,1,1,1,1]
])
shape |> Transformations.rotatey(45)
#Matrex[4×8]
┌ ┐
│ 0.0 0.52532 1.37623 0.8509 0.0 0.52532 1.37623 0.8509 │
│ 0.0 0.0 0.0 0.0 1.0 1.0 1.0 1.0 │
│ 0.0 -0.8509-0.32558 0.52532 0.0 -0.8509-0.32558 0.52532 │
│ 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 │
└ ┘
```
"""
def rotatey(mtx, angle) do
ry = Matrex.new([
[:math.cos(angle),0,:math.sin(angle),0],
[0,1,0,0],
[-:math.sin(angle), 0, :math.cos(angle),0],
[0,0,0,1],
])
Matrex.dot(ry, mtx)
end
@doc """
Rotate a shape by angle about the z axis.
## Examples
```elixir
iex(1)> shape = Transformations.matrix([
[0,1,1,0,0,1,1,0],
[0,0,0,0,1,1,1,1],
[0,0,1,1,0,0,1,1],
[1,1,1,1,1,1,1,1]
])
shape |> Transformations.rotatez(45)
#Matrex[4×8]
┌ ┐
│ 0.0 0.52532 0.52532 0.0 -0.8509-0.32558-0.32558 -0.8509 │
│ 0.0 0.8509 0.8509 0.0 0.52532 1.37623 1.37623 0.52532 │
│ 0.0 0.0 1.0 1.0 0.0 0.0 1.0 1.0 │
│ 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 │
└ ┘
```
"""
def rotatez(mtx, angle) do
rz = Matrex.new([
[:math.cos(angle),-:math.sin(angle),0,0],
[:math.sin(angle), :math.cos(angle),0,0],
[0,0,1,0],
[0,0,0,1],
])
Matrex.dot(rz, mtx)
end
@doc """
Shear a shape by a factor of sy, sz along the y and z axes about the x axis.
## Examples
```elixir
iex(1)> shape = Transformations.matrix([
[0,1,1,0,0,1,1,0],
[0,0,0,0,1,1,1,1],
[0,0,1,1,0,0,1,1],
[1,1,1,1,1,1,1,1]
])
shape |> Transformations.shearx(2,3)
#Matrex[4×8]
┌ ┐
│ 0.0 1.0 1.0 0.0 0.0 1.0 1.0 0.0 │
│ 0.0 2.0 2.0 0.0 1.0 3.0 3.0 1.0 │
│ 0.0 3.0 4.0 1.0 0.0 3.0 4.0 1.0 │
│ 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 │
└ ┘
```
"""
def shearx(mtx, sy, sz) do
shx = Matrex.new([
[1,sy,sz,0],
[0,1,0,0],
[0,0,1,0],
[0,0,0,1],
])
mtx
|> Matrex.transpose()
|> Matrex.dot(shx)
|> Matrex.transpose()
end
@doc """
Shear a shape by a factor of sx, sz along the x and z axes about the y axis.
## Examples
```elixir
iex(1)> shape = Transformations.matrix([
[0,1,1,0,0,1,1,0],
[0,0,0,0,1,1,1,1],
[0,0,1,1,0,0,1,1],
[1,1,1,1,1,1,1,1]
])
shape |> Transformations.sheary(2,3)
#Matrex[4×8]
┌ ┐
│ 0.0 1.0 1.0 0.0 2.0 3.0 3.0 2.0 │
│ 0.0 0.0 0.0 0.0 1.0 1.0 1.0 1.0 │
│ 0.0 0.0 1.0 1.0 3.0 3.0 4.0 4.0 │
│ 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 │
└ ┘
```
"""
def sheary(mtx, sx, sz) do
shy = Matrex.new([
[1,0,0,0],
[sx,1,sz,0],
[0,0,1,0],
[0,0,0,1],
])
mtx
|> Matrex.transpose()
|> Matrex.dot(shy)
|> Matrex.transpose()
end
@doc """
Shear a shape by a factor of sx, sy along the x and y axes about the z axis.
## Examples
```elixir
iex(1)> shape = Transformations.matrix([
[0,1,1,0,0,1,1,0],
[0,0,0,0,1,1,1,1],
[0,0,1,1,0,0,1,1],
[1,1,1,1,1,1,1,1]
])
shape |> Transformations.shearz(2,3)
#Matrex[4×8]
┌ ┐
│ 0.0 1.0 3.0 2.0 0.0 1.0 3.0 2.0 │
│ 0.0 0.0 3.0 3.0 1.0 1.0 4.0 4.0 │
│ 0.0 0.0 1.0 1.0 0.0 0.0 1.0 1.0 │
│ 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 │
└ ┘
```
"""
def shearz(mtx, sx, sy) do
shz = Matrex.new([
[1,0,0,0],
[0,1,0,0],
[sx,sy,1,0],
[0,0,0,1],
])
mtx
|> Matrex.transpose()
|> Matrex.dot(shz)
|> Matrex.transpose()
end
@doc """
Mirror a shape around the yz plane or the x-axis.
## Examples
```elixir
iex(1)> shape = Transformations.matrix([
[0,1,1,0,0,1,1,0],
[0,0,0,0,1,1,1,1],
[0,0,1,1,0,0,1,1],
[1,1,1,1,1,1,1,1]
])
shape |> Transformations.mirrorx()
#Matrex[4×8]
┌ ┐
│ 0.0 -1.0 -1.0 0.0 0.0 -1.0 -1.0 0.0 │
│ 0.0 0.0 0.0 0.0 1.0 1.0 1.0 1.0 │
│ 0.0 0.0 1.0 1.0 0.0 0.0 1.0 1.0 │
│ 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 │
└ ┘
```
"""
def mirrorx(mtx) do
m = Matrex.new([
[-1,0,0,0],
[0,1,0,0],
[0,0,1,0],
[0,0,0,1],
])
Matrex.dot(m, mtx)
end
@doc """
Mirror a shape around the xz plane or the y-axis.
## Examples
```elixir
iex(1)> shape = Transformations.matrix([
[0,1,1,0,0,1,1,0],
[0,0,0,0,1,1,1,1],
[0,0,1,1,0,0,1,1],
[1,1,1,1,1,1,1,1]
])
shape |> Transformations.mirrory()
#Matrex[4×8]
┌ ┐
│ 0.0 1.0 1.0 0.0 0.0 1.0 1.0 0.0 │
│ 0.0 0.0 0.0 0.0 -1.0 -1.0 -1.0 -1.0 │
│ 0.0 0.0 1.0 1.0 0.0 0.0 1.0 1.0 │
│ 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 │
└ ┘
```
"""
def mirrory(mtx) do
m = Matrex.new([
[1,0,0,0],
[0,-1,0,0],
[0,0,1,0],
[0,0,0,1],
])
Matrex.dot(m, mtx)
end
@doc """
Mirror a shape around the xy plane or the z-axis.
## Examples
```elixir
iex(1)> shape = Transformations.matrix([
[0,1,1,0,0,1,1,0],
[0,0,0,0,1,1,1,1],
[0,0,1,1,0,0,1,1],
[1,1,1,1,1,1,1,1]
])
shape |> Transformations.mirrorz()
#Matrex[4×8]
┌ ┐
│ 0.0 1.0 1.0 0.0 0.0 1.0 1.0 0.0 │
│ 0.0 0.0 0.0 0.0 1.0 1.0 1.0 1.0 │
│ 0.0 0.0 -1.0 -1.0 0.0 0.0 -1.0 -1.0 │
│ 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 │
└ ┘
```
"""
def mirrorz(mtx) do
m = Matrex.new([
[1,0,0,0],
[0,1,0,0],
[0,0,-1,0],
[0,0,0,1],
])
Matrex.dot(m, mtx)
end
@doc """
Project a shape down to the yz plane.
## Examples
```elixir
iex(1)> shape = Transformations.matrix([
[0,1,1,0,0,1,1,0],
[0,0,0,0,1,1,1,1],
[0,0,1,1,0,0,1,1],
[1,1,1,1,1,1,1,1]
])
shape |> Transformations.projectx()
#Matrex[4×8]
┌ ┐
│ 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 │
│ 0.0 0.0 0.0 0.0 1.0 1.0 1.0 1.0 │
│ 0.0 0.0 1.0 1.0 0.0 0.0 1.0 1.0 │
│ 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 │
└ ┘
```
"""
def projectx(mtx) do
m = Matrex.new([
[0,0,0,0],
[0,1,0,0],
[0,0,1,0],
[0,0,0,1],
])
Matrex.dot(m, mtx)
end
@doc """
Project a shape down to the xz plane.
## Examples
```elixir
iex(1)> shape = Transformations.matrix([
[0,1,1,0,0,1,1,0],
[0,0,0,0,1,1,1,1],
[0,0,1,1,0,0,1,1],
[1,1,1,1,1,1,1,1]
])
shape |> Transformations.projecty()
#Matrex[4×8]
┌ ┐
│ 0.0 1.0 1.0 0.0 0.0 1.0 1.0 0.0 │
│ 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 │
│ 0.0 0.0 1.0 1.0 0.0 0.0 1.0 1.0 │
│ 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 │
└ ┘
```
"""
def projecty(mtx) do
m = Matrex.new([
[1,0,0,0],
[0,0,0,0],
[0,0,1,0],
[0,0,0,1],
])
Matrex.dot(m, mtx)
end
@doc """
Project a shape down to the xy plane.
## Examples
```elixir
iex(1)> shape = Transformations.matrix([
[0,1,1,0,0,1,1,0],
[0,0,0,0,1,1,1,1],
[0,0,1,1,0,0,1,1],
[1,1,1,1,1,1,1,1]
])
shape |> Transformations.projectz()
#Matrex[4×8]
┌ ┐
│ 0.0 1.0 1.0 0.0 0.0 1.0 1.0 0.0 │
│ 0.0 0.0 0.0 0.0 1.0 1.0 1.0 1.0 │
│ 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 │
│ 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 │
└ ┘
```
"""
def projectz(mtx) do
m = Matrex.new([
[1,0,0,0],
[0,1,0,0],
[0,0,0,0],
[0,0,0,1],
])
Matrex.dot(m, mtx)
end
end