mirror of
https://github.com/SleepingInsomniac/pixelfaucet
synced 2025-01-18 22:26:32 +01:00
Improve transform2d
This commit is contained in:
parent
5456adad4e
commit
67ad23efe3
3 changed files with 149 additions and 74 deletions
|
@ -38,6 +38,8 @@ module PF
|
|||
end
|
||||
end
|
||||
|
||||
delegate :fill, to: @values
|
||||
|
||||
def initialize
|
||||
@values = Slice(T).new(W * H, T.new(0))
|
||||
end
|
||||
|
@ -55,6 +57,16 @@ module PF
|
|||
nums.each_with_index { |n, i| @values[i] = n }
|
||||
end
|
||||
|
||||
def reset_to_identity!
|
||||
{% unless W == H %}
|
||||
raise "Matrix({{W}}x{{H}}) is not square"
|
||||
{% end %}
|
||||
fill(T.new(0))
|
||||
{% for i in 0...W %}
|
||||
self[{{i}}, {{i}}] = T.new(1)
|
||||
{% end %}
|
||||
end
|
||||
|
||||
# Width of the matrix
|
||||
def width
|
||||
W
|
||||
|
@ -66,11 +78,7 @@ module PF
|
|||
end
|
||||
|
||||
def size
|
||||
{% if W == H %}
|
||||
W
|
||||
{% else %}
|
||||
raise "Matrix({{W}}x{{H}}) is not square"
|
||||
{% end %}
|
||||
W * H
|
||||
end
|
||||
|
||||
# Tests the equality of two matricies
|
||||
|
@ -102,7 +110,7 @@ module PF
|
|||
end
|
||||
|
||||
def *(other : Matrix)
|
||||
result = Matrix(T, W, H).new
|
||||
result = Matrix(typeof(self[0, 0] * other[0, 0]), W, H).new
|
||||
{% for y in (0...H) %}
|
||||
{% for x in (0...W) %}
|
||||
{% for n in (0...W) %}
|
||||
|
@ -113,14 +121,16 @@ module PF
|
|||
result
|
||||
end
|
||||
|
||||
def inspect
|
||||
String.build do |io|
|
||||
H.times do |h|
|
||||
io << '['
|
||||
W.times { |w| io << self[w, h] }
|
||||
io << "]\n"
|
||||
def to_s(io)
|
||||
io << {{ @type }} << '['
|
||||
(0...H).each do |y|
|
||||
(0...W).each do |x|
|
||||
io << self[x, y]
|
||||
io << ' ' unless x == W - 1
|
||||
end
|
||||
io << ", " unless y == H - 1
|
||||
end
|
||||
io << ']'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,73 +3,155 @@ require "./vector"
|
|||
|
||||
module PF
|
||||
class Transform2d
|
||||
property matrix : Matrix(Float64, 3, 3) = Matrix[
|
||||
1.0, 0.0, 0.0,
|
||||
0.0, 1.0, 0.0,
|
||||
0.0, 0.0, 1.0,
|
||||
]
|
||||
property matrix : Matrix(Float64, 3, 3)
|
||||
|
||||
def self.identity
|
||||
Matrix[
|
||||
1.0, 0.0, 0.0,
|
||||
0.0, 1.0, 0.0,
|
||||
0.0, 0.0, 1.0,
|
||||
]
|
||||
end
|
||||
|
||||
# Returns a matrix representing a 2d translation
|
||||
def self.translation(x : Float | Int, y : Float | Int)
|
||||
Matrix[
|
||||
1.0, 0.0, x.to_f64,
|
||||
0.0, 1.0, y.to_f64,
|
||||
0.0, 0.0, 1.0,
|
||||
]
|
||||
end
|
||||
|
||||
# Returns a matrix representing a 2d scaling
|
||||
def self.scale(x : Float | Int, y : Float | Int)
|
||||
Matrix[
|
||||
x.to_f64, 0.0, 0.0,
|
||||
0.0, y.to_f64, 0.0,
|
||||
0.0, 0.0, 1.0,
|
||||
]
|
||||
end
|
||||
|
||||
# Returns a matrix representing a 2d rotation
|
||||
def self.rotation(angle : Float | Int)
|
||||
cos = Math.cos(angle)
|
||||
sin = Math.sin(angle)
|
||||
Matrix[
|
||||
cos, -sin, 0.0,
|
||||
sin, cos, 0.0,
|
||||
0.0, 0.0, 1.0,
|
||||
]
|
||||
end
|
||||
|
||||
# Returns a matrix representing a 2d shear
|
||||
def self.shear(x : Float | Int, y : Float | Int)
|
||||
Matrix[
|
||||
1.0, x.to_f64, 0.0,
|
||||
y.to_f64, 1.0, 0.0,
|
||||
0.0, 0.0, 1.0,
|
||||
]
|
||||
end
|
||||
|
||||
# Return a new inverted version of the given *matrix*
|
||||
def self.invert(matrix : Matrix)
|
||||
det = matrix[0, 0] * (matrix[1, 1] * matrix[2, 2] - matrix[1, 2] * matrix[2, 1]) -
|
||||
matrix[1, 0] * (matrix[0, 1] * matrix[2, 2] - matrix[2, 1] * matrix[0, 2]) +
|
||||
matrix[2, 0] * (matrix[0, 1] * matrix[1, 2] - matrix[1, 1] * matrix[0, 2])
|
||||
|
||||
idet = 1.0 / det
|
||||
|
||||
Matrix[
|
||||
(matrix[1, 1] * matrix[2, 2] - matrix[1, 2] * matrix[2, 1]) * idet,
|
||||
(matrix[2, 0] * matrix[1, 2] - matrix[1, 0] * matrix[2, 2]) * idet,
|
||||
(matrix[1, 0] * matrix[2, 1] - matrix[2, 0] * matrix[1, 1]) * idet,
|
||||
|
||||
(matrix[2, 1] * matrix[0, 2] - matrix[0, 1] * matrix[2, 2]) * idet,
|
||||
(matrix[0, 0] * matrix[2, 2] - matrix[2, 0] * matrix[0, 2]) * idet,
|
||||
(matrix[0, 1] * matrix[2, 0] - matrix[0, 0] * matrix[2, 1]) * idet,
|
||||
|
||||
(matrix[0, 1] * matrix[1, 2] - matrix[0, 2] * matrix[1, 1]) * idet,
|
||||
(matrix[0, 2] * matrix[1, 0] - matrix[0, 0] * matrix[1, 2]) * idet,
|
||||
(matrix[0, 0] * matrix[1, 1] - matrix[0, 1] * matrix[1, 0]) * idet,
|
||||
]
|
||||
end
|
||||
|
||||
def initialize
|
||||
@matrix = PF::Transform2d.identity
|
||||
end
|
||||
|
||||
def initialize(@matrix)
|
||||
end
|
||||
|
||||
# =============
|
||||
|
||||
# Reset the transformation to the identity matrix
|
||||
def reset
|
||||
@matrix = Matrix[
|
||||
1.0, 0.0, 0.0,
|
||||
0.0, 1.0, 0.0,
|
||||
0.0, 0.0, 1.0,
|
||||
]
|
||||
@matrix = PF::Transform2d.identity
|
||||
self
|
||||
end
|
||||
|
||||
def translate(x : Float | Int, y : Float | Int)
|
||||
@matrix = Matrix[
|
||||
1.0, 0.0, x.to_f64,
|
||||
0.0, 1.0, y.to_f64,
|
||||
0.0, 0.0, 1.0,
|
||||
] * @matrix
|
||||
# =============
|
||||
# = translate =
|
||||
# =============
|
||||
|
||||
# Translate by *x* and *y*
|
||||
def translate(x : Number, y : Number)
|
||||
@matrix = PF::Transform2d.translation(x, y) * @matrix
|
||||
self
|
||||
end
|
||||
|
||||
def translate(to : Vector2)
|
||||
translate(to.x, to.y)
|
||||
# ditto
|
||||
def translate(point : Vector2)
|
||||
translate(point.x, point.y)
|
||||
end
|
||||
|
||||
# ==========
|
||||
# = rotate =
|
||||
# ==========
|
||||
|
||||
# Rotate by *angle* (in radians)
|
||||
def rotate(angle : Float | Int)
|
||||
@matrix = PF::Transform2d.rotation(angle) * @matrix
|
||||
self
|
||||
end
|
||||
|
||||
# =========
|
||||
# = scale =
|
||||
# =========
|
||||
|
||||
# Scale by *x* and *y*
|
||||
def scale(x : Float | Int, y : Float | Int)
|
||||
@matrix = Matrix[
|
||||
x.to_f64, 0.0, 0.0,
|
||||
0.0, y.to_f64, 0.0,
|
||||
0.0, 0.0, 1.0,
|
||||
] * @matrix
|
||||
@matrix = PF::Transform2d.scale(x, y) * @matrix
|
||||
self
|
||||
end
|
||||
|
||||
def scale(n : Float | Int)
|
||||
# ditto
|
||||
def scale(point : Vector2)
|
||||
scale(point.x, point.y)
|
||||
end
|
||||
|
||||
# Scale both x and y by *n*
|
||||
def scale(n : Number)
|
||||
scale(n, n)
|
||||
end
|
||||
|
||||
def rotate(angle : Float | Int)
|
||||
cos = Math.cos(angle)
|
||||
sin = Math.sin(angle)
|
||||
@matrix = Matrix[
|
||||
cos, -sin, 0.0,
|
||||
sin, cos, 0.0,
|
||||
0.0, 0.0, 1.0,
|
||||
] * @matrix
|
||||
self
|
||||
end
|
||||
# =========
|
||||
# = shear =
|
||||
# =========
|
||||
|
||||
# Shear by *x* and *y*
|
||||
def shear(x : Float | Int, y : Float | Int)
|
||||
@matrix = Matrix[
|
||||
1.0, x.to_f64, 0.0,
|
||||
y.to_f64, 1.0, 0.0,
|
||||
0.0, 0.0, 1.0,
|
||||
] * @matrix
|
||||
@matrix = PF::Transform2d.shear(x, y) * @matrix
|
||||
self
|
||||
end
|
||||
|
||||
# ditto
|
||||
def shear(point : Vector2)
|
||||
shear(point.x, point.y)
|
||||
end
|
||||
|
||||
# ==========
|
||||
|
||||
# Return the boudning box of the current transformation matrix
|
||||
def bounding_box(x : Float | Int, y : Float | Int)
|
||||
top_left = apply(0.0, 0.0)
|
||||
top_right = apply(x.to_f, 0.0)
|
||||
|
@ -82,31 +164,14 @@ module PF
|
|||
{Vector[xs.min, ys.min], Vector[xs.max, ys.max]}
|
||||
end
|
||||
|
||||
# Invert the transformation
|
||||
def invert
|
||||
det = @matrix[0, 0] * (@matrix[1, 1] * @matrix[2, 2] - @matrix[1, 2] * @matrix[2, 1]) -
|
||||
@matrix[1, 0] * (@matrix[0, 1] * @matrix[2, 2] - @matrix[2, 1] * @matrix[0, 2]) +
|
||||
@matrix[2, 0] * (@matrix[0, 1] * @matrix[1, 2] - @matrix[1, 1] * @matrix[0, 2])
|
||||
|
||||
idet = 1.0 / det
|
||||
|
||||
@matrix = Matrix[
|
||||
(@matrix[1, 1] * @matrix[2, 2] - @matrix[1, 2] * @matrix[2, 1]) * idet,
|
||||
(@matrix[2, 0] * @matrix[1, 2] - @matrix[1, 0] * @matrix[2, 2]) * idet,
|
||||
(@matrix[1, 0] * @matrix[2, 1] - @matrix[2, 0] * @matrix[1, 1]) * idet,
|
||||
|
||||
(@matrix[2, 1] * @matrix[0, 2] - @matrix[0, 1] * @matrix[2, 2]) * idet,
|
||||
(@matrix[0, 0] * @matrix[2, 2] - @matrix[2, 0] * @matrix[0, 2]) * idet,
|
||||
(@matrix[0, 1] * @matrix[2, 0] - @matrix[0, 0] * @matrix[2, 1]) * idet,
|
||||
|
||||
(@matrix[0, 1] * @matrix[1, 2] - @matrix[0, 2] * @matrix[1, 1]) * idet,
|
||||
(@matrix[0, 2] * @matrix[1, 0] - @matrix[0, 0] * @matrix[1, 2]) * idet,
|
||||
(@matrix[0, 0] * @matrix[1, 1] - @matrix[0, 1] * @matrix[1, 0]) * idet,
|
||||
]
|
||||
@matrix = PF::Transform2d.invert(@matrix)
|
||||
self
|
||||
end
|
||||
|
||||
def apply(x : Float | Int, y : Float | Int)
|
||||
result = Vector[x, y, typeof(x, y).new(1)] * @matrix
|
||||
result = Vector[x, y, 1.0] * @matrix
|
||||
Vector[result.x, result.y]
|
||||
end
|
||||
|
||||
|
|
|
@ -139,8 +139,8 @@ module PF
|
|||
# # => PF::Vector3(Int32)(@x=1, @y=4, @z=3)
|
||||
# ```
|
||||
def *(matrix : Matrix)
|
||||
PF::Vector[{% for col in 0...i %}
|
||||
{% for row in 0...i %} @{{ vars[row].id }} * matrix[{{row}}, {{col}}] {% if row != i - 1 %} + {% end %}{% end %},
|
||||
PF::Vector[{% for row in 0...i %}
|
||||
{% for col in 0...i %} @{{ vars[col].id }} * matrix[{{col}}, {{row}}] {% if col != i - 1 %} + {% end %}{% end %},
|
||||
{% end %}]
|
||||
end
|
||||
|
||||
|
@ -150,7 +150,7 @@ module PF
|
|||
to_u8: UInt8, to_u16: UInt16, to_u32: UInt32, to_u64: UInt64, to_u128: UInt128,
|
||||
to_f32: Float32, to_f64: Float64,
|
||||
} %}
|
||||
# Convert this vector to {{ type }}
|
||||
# Convert the components in this vector to {{ type }}
|
||||
def {{ method }}
|
||||
Vector{{i}}({{ type }}).new({% for arg in 0...i %} @{{vars[arg].id}}.{{method}}, {% end %})
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue