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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
delegate :fill, to: @values
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
@values = Slice(T).new(W * H, T.new(0))
|
@values = Slice(T).new(W * H, T.new(0))
|
||||||
end
|
end
|
||||||
|
@ -55,6 +57,16 @@ module PF
|
||||||
nums.each_with_index { |n, i| @values[i] = n }
|
nums.each_with_index { |n, i| @values[i] = n }
|
||||||
end
|
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
|
# Width of the matrix
|
||||||
def width
|
def width
|
||||||
W
|
W
|
||||||
|
@ -66,11 +78,7 @@ module PF
|
||||||
end
|
end
|
||||||
|
|
||||||
def size
|
def size
|
||||||
{% if W == H %}
|
W * H
|
||||||
W
|
|
||||||
{% else %}
|
|
||||||
raise "Matrix({{W}}x{{H}}) is not square"
|
|
||||||
{% end %}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Tests the equality of two matricies
|
# Tests the equality of two matricies
|
||||||
|
@ -102,7 +110,7 @@ module PF
|
||||||
end
|
end
|
||||||
|
|
||||||
def *(other : Matrix)
|
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 y in (0...H) %}
|
||||||
{% for x in (0...W) %}
|
{% for x in (0...W) %}
|
||||||
{% for n in (0...W) %}
|
{% for n in (0...W) %}
|
||||||
|
@ -113,14 +121,16 @@ module PF
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
def inspect
|
def to_s(io)
|
||||||
String.build do |io|
|
io << {{ @type }} << '['
|
||||||
H.times do |h|
|
(0...H).each do |y|
|
||||||
io << '['
|
(0...W).each do |x|
|
||||||
W.times { |w| io << self[w, h] }
|
io << self[x, y]
|
||||||
io << "]\n"
|
io << ' ' unless x == W - 1
|
||||||
end
|
end
|
||||||
|
io << ", " unless y == H - 1
|
||||||
end
|
end
|
||||||
|
io << ']'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,73 +3,155 @@ require "./vector"
|
||||||
|
|
||||||
module PF
|
module PF
|
||||||
class Transform2d
|
class Transform2d
|
||||||
property matrix : Matrix(Float64, 3, 3) = Matrix[
|
property matrix : Matrix(Float64, 3, 3)
|
||||||
1.0, 0.0, 0.0,
|
|
||||||
0.0, 1.0, 0.0,
|
def self.identity
|
||||||
0.0, 0.0, 1.0,
|
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
|
def initialize
|
||||||
|
@matrix = PF::Transform2d.identity
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize(@matrix)
|
def initialize(@matrix)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# =============
|
||||||
|
|
||||||
|
# Reset the transformation to the identity matrix
|
||||||
def reset
|
def reset
|
||||||
@matrix = Matrix[
|
@matrix = PF::Transform2d.identity
|
||||||
1.0, 0.0, 0.0,
|
|
||||||
0.0, 1.0, 0.0,
|
|
||||||
0.0, 0.0, 1.0,
|
|
||||||
]
|
|
||||||
self
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
def translate(x : Float | Int, y : Float | Int)
|
# =============
|
||||||
@matrix = Matrix[
|
# = translate =
|
||||||
1.0, 0.0, x.to_f64,
|
# =============
|
||||||
0.0, 1.0, y.to_f64,
|
|
||||||
0.0, 0.0, 1.0,
|
# Translate by *x* and *y*
|
||||||
] * @matrix
|
def translate(x : Number, y : Number)
|
||||||
|
@matrix = PF::Transform2d.translation(x, y) * @matrix
|
||||||
self
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
def translate(to : Vector2)
|
# ditto
|
||||||
translate(to.x, to.y)
|
def translate(point : Vector2)
|
||||||
|
translate(point.x, point.y)
|
||||||
end
|
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)
|
def scale(x : Float | Int, y : Float | Int)
|
||||||
@matrix = Matrix[
|
@matrix = PF::Transform2d.scale(x, y) * @matrix
|
||||||
x.to_f64, 0.0, 0.0,
|
|
||||||
0.0, y.to_f64, 0.0,
|
|
||||||
0.0, 0.0, 1.0,
|
|
||||||
] * @matrix
|
|
||||||
self
|
self
|
||||||
end
|
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)
|
scale(n, n)
|
||||||
end
|
end
|
||||||
|
|
||||||
def rotate(angle : Float | Int)
|
# =========
|
||||||
cos = Math.cos(angle)
|
# = shear =
|
||||||
sin = Math.sin(angle)
|
# =========
|
||||||
@matrix = Matrix[
|
|
||||||
cos, -sin, 0.0,
|
|
||||||
sin, cos, 0.0,
|
|
||||||
0.0, 0.0, 1.0,
|
|
||||||
] * @matrix
|
|
||||||
self
|
|
||||||
end
|
|
||||||
|
|
||||||
|
# Shear by *x* and *y*
|
||||||
def shear(x : Float | Int, y : Float | Int)
|
def shear(x : Float | Int, y : Float | Int)
|
||||||
@matrix = Matrix[
|
@matrix = PF::Transform2d.shear(x, y) * @matrix
|
||||||
1.0, x.to_f64, 0.0,
|
|
||||||
y.to_f64, 1.0, 0.0,
|
|
||||||
0.0, 0.0, 1.0,
|
|
||||||
] * @matrix
|
|
||||||
self
|
self
|
||||||
end
|
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)
|
def bounding_box(x : Float | Int, y : Float | Int)
|
||||||
top_left = apply(0.0, 0.0)
|
top_left = apply(0.0, 0.0)
|
||||||
top_right = apply(x.to_f, 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]}
|
{Vector[xs.min, ys.min], Vector[xs.max, ys.max]}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Invert the transformation
|
||||||
def invert
|
def invert
|
||||||
det = @matrix[0, 0] * (@matrix[1, 1] * @matrix[2, 2] - @matrix[1, 2] * @matrix[2, 1]) -
|
@matrix = PF::Transform2d.invert(@matrix)
|
||||||
@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,
|
|
||||||
]
|
|
||||||
self
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
def apply(x : Float | Int, y : Float | Int)
|
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]
|
Vector[result.x, result.y]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -139,8 +139,8 @@ module PF
|
||||||
# # => PF::Vector3(Int32)(@x=1, @y=4, @z=3)
|
# # => PF::Vector3(Int32)(@x=1, @y=4, @z=3)
|
||||||
# ```
|
# ```
|
||||||
def *(matrix : Matrix)
|
def *(matrix : Matrix)
|
||||||
PF::Vector[{% for col in 0...i %}
|
PF::Vector[{% for row in 0...i %}
|
||||||
{% for row in 0...i %} @{{ vars[row].id }} * matrix[{{row}}, {{col}}] {% if row != i - 1 %} + {% end %}{% end %},
|
{% for col in 0...i %} @{{ vars[col].id }} * matrix[{{col}}, {{row}}] {% if col != i - 1 %} + {% end %}{% end %},
|
||||||
{% 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_u8: UInt8, to_u16: UInt16, to_u32: UInt32, to_u64: UInt64, to_u128: UInt128,
|
||||||
to_f32: Float32, to_f64: Float64,
|
to_f32: Float32, to_f64: Float64,
|
||||||
} %}
|
} %}
|
||||||
# Convert this vector to {{ type }}
|
# Convert the components in this vector to {{ type }}
|
||||||
def {{ method }}
|
def {{ method }}
|
||||||
Vector{{i}}({{ type }}).new({% for arg in 0...i %} @{{vars[arg].id}}.{{method}}, {% end %})
|
Vector{{i}}({{ type }}).new({% for arg in 0...i %} @{{vars[arg].id}}.{{method}}, {% end %})
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue