#159 Fix unproject for rotated matrix
This commit is contained in:
parent
20b05d9ec2
commit
cabaee680e
12
geometry.go
12
geometry.go
|
@ -401,13 +401,11 @@ func (m Matrix) Project(u Vec) Vec {
|
||||||
|
|
||||||
// Unproject does the inverse operation to Project.
|
// Unproject does the inverse operation to Project.
|
||||||
//
|
//
|
||||||
// It turns out that multiplying a vector by the inverse matrix of m can be nearly-accomplished by
|
|
||||||
// subtracting the translate part of the matrix and multplying by the inverse of the top-left 2x2
|
|
||||||
// matrix, and the inverse of a 2x2 matrix is simple enough to just be inlined in the computation.
|
|
||||||
//
|
|
||||||
// Time complexity is O(1).
|
// Time complexity is O(1).
|
||||||
func (m Matrix) Unproject(u Vec) Vec {
|
func (m Matrix) Unproject(u Vec) Vec {
|
||||||
d := (m[0] * m[3]) - (m[1] * m[2])
|
det := m[0]*m[3] - m[2]*m[1]
|
||||||
u.X, u.Y = (u.X-m[4])/d, (u.Y-m[5])/d
|
return Vec{
|
||||||
return Vec{u.X*m[3] - u.Y*m[1], u.Y*m[0] - u.X*m[2]}
|
m[3]/det*u.X - m[2]/det*u.Y + m[2]*m[5] - m[3]*m[4],
|
||||||
|
-m[1]/det*u.X + m[0]/det*u.Y + m[1]*m[4] - m[0]*m[5],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@ package pixel_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"math"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/faiface/pixel"
|
"github.com/faiface/pixel"
|
||||||
|
@ -77,3 +79,30 @@ func TestResizeRect(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestMatrix_Unproject(t *testing.T) {
|
||||||
|
t.Run("for rotated matrix", func(t *testing.T) {
|
||||||
|
matrix := pixel.IM.Rotated(pixel.ZV, math.Pi/2)
|
||||||
|
unprojected := matrix.Unproject(pixel.V(0, 1))
|
||||||
|
assert.InDelta(t, unprojected.X, 1, 0.01)
|
||||||
|
assert.InDelta(t, unprojected.Y, 0, 0.01)
|
||||||
|
})
|
||||||
|
t.Run("for moved matrix", func(t *testing.T) {
|
||||||
|
matrix := pixel.IM.Moved(pixel.V(5, 5))
|
||||||
|
unprojected := matrix.Unproject(pixel.V(0, 0))
|
||||||
|
assert.InDelta(t, unprojected.X, -5, 0.01)
|
||||||
|
assert.InDelta(t, unprojected.Y, -5, 0.01)
|
||||||
|
})
|
||||||
|
t.Run("for scaled matrix", func(t *testing.T) {
|
||||||
|
matrix := pixel.IM.Scaled(pixel.ZV, 2)
|
||||||
|
unprojected := matrix.Unproject(pixel.V(4, 4))
|
||||||
|
assert.InDelta(t, unprojected.X, 2, 0.01)
|
||||||
|
assert.InDelta(t, unprojected.Y, 2, 0.01)
|
||||||
|
})
|
||||||
|
t.Run("for singular matrix", func(t *testing.T) {
|
||||||
|
matrix := pixel.Matrix{0, 0, 0, 0, 0, 0}
|
||||||
|
unprojected := matrix.Unproject(pixel.ZV)
|
||||||
|
assert.True(t, math.IsNaN(unprojected.X))
|
||||||
|
assert.True(t, math.IsNaN(unprojected.Y))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue