123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376 |
- // Copyright 2014 Hajime Hoshi
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- package ebiten_test
- import (
- "fmt"
- "math"
- "testing"
- . "github.com/hajimehoshi/ebiten/v2"
- )
- func TestGeoMInit(t *testing.T) {
- var m GeoM
- for i := 0; i < GeoMDim-1; i++ {
- for j := 0; j < GeoMDim; j++ {
- got := m.Element(i, j)
- want := 0.0
- if i == j {
- want = 1
- }
- if want != got {
- t.Errorf("m.Element(%d, %d) = %f, want %f", i, j, got, want)
- }
- }
- }
- }
- func TestGeoMAssign(t *testing.T) {
- m := GeoM{}
- m.SetElement(0, 0, 1)
- m2 := m
- m.SetElement(0, 0, 0)
- got := m2.Element(0, 0)
- want := 1.0
- if want != got {
- t.Errorf("m2.Element(%d, %d) = %f, want %f", 0, 0, got, want)
- }
- }
- func TestGeoMConcat(t *testing.T) {
- matrix1 := GeoM{}
- matrix1.Scale(2, 2)
- matrix2 := GeoM{}
- matrix2.Translate(1, 1)
- matrix3 := matrix1
- matrix3.Concat(matrix2)
- expected := [][]float64{
- {2, 0, 1},
- {0, 2, 1},
- }
- for i := 0; i < 2; i++ {
- for j := 0; j < 3; j++ {
- got := matrix3.Element(i, j)
- want := expected[i][j]
- if want != got {
- t.Errorf("matrix3.Element(%d, %d) = %f,"+
- " want %f",
- i, j, got, want)
- }
- }
- }
- matrix4 := matrix2
- matrix4.Concat(matrix1)
- expected = [][]float64{
- {2, 0, 2},
- {0, 2, 2},
- }
- for i := 0; i < 2; i++ {
- for j := 0; j < 3; j++ {
- got := matrix4.Element(i, j)
- want := expected[i][j]
- if want != got {
- t.Errorf("matrix4.Element(%d, %d) = %f, want %f",
- i, j, got, want)
- }
- }
- }
- }
- func TestGeoMConcatSelf(t *testing.T) {
- m := GeoM{}
- m.SetElement(0, 0, 1)
- m.SetElement(0, 1, 2)
- m.SetElement(0, 2, 3)
- m.SetElement(1, 0, 4)
- m.SetElement(1, 1, 5)
- m.SetElement(1, 2, 6)
- m.Concat(m)
- expected := [][]float64{
- {9, 12, 18},
- {24, 33, 48},
- }
- for i := 0; i < 2; i++ {
- for j := 0; j < 3; j++ {
- got := m.Element(i, j)
- want := expected[i][j]
- if want != got {
- t.Errorf("m.Element(%d, %d) = %f, want %f",
- i, j, got, want)
- }
- }
- }
- }
- func geoMToString(g GeoM) string {
- a := g.Element(0, 0)
- b := g.Element(0, 1)
- c := g.Element(1, 0)
- d := g.Element(1, 1)
- tx := g.Element(0, 2)
- ty := g.Element(1, 2)
- return fmt.Sprintf("{a: %f, b: %f, c: %f, d: %f, tx: %f, ty: %f}", a, b, c, d, tx, ty)
- }
- func TestGeoMApply(t *testing.T) {
- trans := GeoM{}
- trans.Translate(1, 2)
- scale := GeoM{}
- scale.Scale(1.5, 2.5)
- cpx := GeoM{}
- cpx.Rotate(math.Pi)
- cpx.Scale(1.5, 2.5)
- cpx.Translate(-2, -3)
- cases := []struct {
- GeoM GeoM
- InX float64
- InY float64
- OutX float64
- OutY float64
- }{
- {
- GeoM: GeoM{},
- InX: 3.14159,
- InY: 2.81828,
- OutX: 3.14159,
- OutY: 2.81828,
- },
- {
- GeoM: trans,
- InX: 3.14159,
- InY: 2.81828,
- OutX: 4.14159,
- OutY: 4.81828,
- },
- {
- GeoM: scale,
- InX: 3.14159,
- InY: 2.81828,
- OutX: 4.71239,
- OutY: 7.04570,
- },
- {
- GeoM: cpx,
- InX: 3.14159,
- InY: 2.81828,
- OutX: -6.71239,
- OutY: -10.04570,
- },
- }
- const delta = 0.00001
- for _, c := range cases {
- rx, ry := c.GeoM.Apply(c.InX, c.InY)
- if math.Abs(rx-c.OutX) > delta || math.Abs(ry-c.OutY) > delta {
- t.Errorf("%s.Apply(%f, %f) = (%f, %f), want (%f, %f)", geoMToString(c.GeoM), c.InX, c.InY, rx, ry, c.OutX, c.OutY)
- }
- }
- }
- func TestGeoMIsInvert(t *testing.T) {
- zero := GeoM{}
- zero.Scale(0, 0)
- trans := GeoM{}
- trans.Translate(1, 2)
- scale := GeoM{}
- scale.Scale(1.5, 2.5)
- cpx := GeoM{}
- cpx.Rotate(math.Pi)
- cpx.Scale(1.5, 2.5)
- cpx.Translate(-2, -3)
- cpx2 := GeoM{}
- cpx2.Scale(2, 3)
- cpx2.Rotate(0.234)
- cpx2.Translate(100, 100)
- skew := GeoM{}
- skew.Skew(1, 1)
- cases := []struct {
- GeoM GeoM
- Invertible bool
- }{
- {
- GeoM: zero,
- Invertible: false,
- },
- {
- GeoM: GeoM{},
- Invertible: true,
- },
- {
- GeoM: trans,
- Invertible: true,
- },
- {
- GeoM: scale,
- Invertible: true,
- },
- {
- GeoM: cpx,
- Invertible: true,
- },
- {
- GeoM: cpx2,
- Invertible: true,
- },
- {
- GeoM: skew,
- Invertible: true,
- },
- }
- pts := []struct {
- X float64
- Y float64
- }{
- {
- X: 0,
- Y: 0,
- },
- {
- X: 1,
- Y: 1,
- },
- {
- X: 3.14159,
- Y: 2.81828,
- },
- {
- X: -1000,
- Y: 1000,
- },
- }
- const delta = 0.001
- for _, c := range cases {
- if c.GeoM.IsInvertible() != c.Invertible {
- t.Errorf("%s.IsInvertible(): got: %t, want: %t", geoMToString(c.GeoM), c.GeoM.IsInvertible(), c.Invertible)
- }
- if !c.GeoM.IsInvertible() {
- continue
- }
- invGeoM := c.GeoM
- invGeoM.Invert()
- for _, p := range pts {
- x, y := p.X, p.Y
- gotX, gotY := invGeoM.Apply(c.GeoM.Apply(x, y))
- if math.Abs(gotX-x) > delta || math.Abs(gotY-y) > delta {
- t.Errorf("%s.Apply(%s.Apply(%f, %f)): got: (%f, %f), want: (%f, %f)", geoMToString(invGeoM), geoMToString(c.GeoM), x, y, gotX, gotY, x, y)
- }
- }
- }
- }
- func newGeoM(a, b, c, d, tx, ty float64) GeoM {
- outp := GeoM{}
- outp.SetElement(0, 0, a)
- outp.SetElement(0, 1, b)
- outp.SetElement(0, 2, tx)
- outp.SetElement(1, 0, c)
- outp.SetElement(1, 1, d)
- outp.SetElement(1, 2, ty)
- return outp
- }
- func TestGeomSkew(t *testing.T) {
- testSkew := func(skewX, skewY float64, input, expected GeoM) {
- input.Skew(skewX, skewY)
- for i := 0; i < 2; i++ {
- for j := 0; j < 3; j++ {
- got := input.Element(i, j)
- want := expected.Element(i, j)
- if want != got {
- t.Errorf("Skew(%f, %f): got %s, want: %s", skewX, skewY, input.String(), expected.String())
- return
- }
- }
- }
- }
- // skewX = 0.25
- expectedX := newGeoM(1, math.Tan(0.25), math.Tan(0), 1, 0, 0)
- testSkew(0.25, 0, GeoM{}, expectedX)
- // skewY = 0.25
- expectedY := newGeoM(1, math.Tan(0), math.Tan(0.5), 1, 0, 0)
- testSkew(0, 0.5, GeoM{}, expectedY)
- // skewX, skewY = 0.3, 0.8
- expectedXY := newGeoM(1, math.Tan(0.3), math.Tan(0.8), 1, 0, 0)
- testSkew(0.3, 0.8, GeoM{}, expectedXY)
- // skewX, skewY = 0.4, -1.8 ; b, c = 2, 3
- expectedOffDiag := newGeoM(1+3*math.Tan(0.4), 2+math.Tan(0.4), 3+math.Tan(-1.8), 1+2*math.Tan(-1.8), 0, 0)
- inputOffDiag := newGeoM(1, 2, 3, 1, 0, 0)
- testSkew(0.4, -1.8, inputOffDiag, expectedOffDiag)
- // skewX, skewY = -1.5, 1.5 ; tx, ty = 5, 6
- expectedTrn := newGeoM(1, math.Tan(-1.5), math.Tan(1.5), 1, 5+math.Tan(-1.5)*6, 6+5*math.Tan(1.5))
- inputTrn := newGeoM(1, 0, 0, 1, 5, 6)
- testSkew(-1.5, 1.5, inputTrn, expectedTrn)
- }
- func TestGeoMEquals(t *testing.T) {
- tests := []struct {
- a GeoM
- b GeoM
- want bool
- }{
- {
- a: GeoM{},
- b: GeoM{},
- want: true,
- },
- {
- a: newGeoM(3, 1, 4, 1, 5, 9),
- b: newGeoM(3, 1, 4, 1, 5, 9),
- want: true,
- },
- {
- a: newGeoM(3, 1, 4, 1, 5, 9),
- b: newGeoM(3, 1, 4, 1, 5, 10),
- want: false,
- },
- }
- for _, test := range tests {
- got := (test.a == test.b)
- want := test.want
- if got != want {
- t.Errorf("%#v == %#v: got %t, want: %t", test.a, test.b, got, want)
- }
- }
- }
- func BenchmarkGeoM(b *testing.B) {
- var m GeoM
- for i := 0; i < b.N; i++ {
- m = GeoM{}
- m.Translate(10, 20)
- m.Scale(2, 3)
- m.Rotate(math.Pi / 2)
- }
- }
|