geom_test.go 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. // Copyright 2014 Hajime Hoshi
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package ebiten_test
  15. import (
  16. "fmt"
  17. "math"
  18. "testing"
  19. "github.com/hajimehoshi/ebiten/v2"
  20. )
  21. func TestGeoMInit(t *testing.T) {
  22. var m ebiten.GeoM
  23. for i := 0; i < ebiten.GeoMDim-1; i++ {
  24. for j := 0; j < ebiten.GeoMDim; j++ {
  25. got := m.Element(i, j)
  26. want := 0.0
  27. if i == j {
  28. want = 1
  29. }
  30. if want != got {
  31. t.Errorf("m.Element(%d, %d) = %f, want %f", i, j, got, want)
  32. }
  33. }
  34. }
  35. }
  36. func TestGeoMAssign(t *testing.T) {
  37. m := ebiten.GeoM{}
  38. m.SetElement(0, 0, 1)
  39. m2 := m
  40. m.SetElement(0, 0, 0)
  41. got := m2.Element(0, 0)
  42. want := 1.0
  43. if want != got {
  44. t.Errorf("m2.Element(%d, %d) = %f, want %f", 0, 0, got, want)
  45. }
  46. }
  47. func TestGeoMConcat(t *testing.T) {
  48. matrix1 := ebiten.GeoM{}
  49. matrix1.Scale(2, 2)
  50. matrix2 := ebiten.GeoM{}
  51. matrix2.Translate(1, 1)
  52. matrix3 := matrix1
  53. matrix3.Concat(matrix2)
  54. expected := [][]float64{
  55. {2, 0, 1},
  56. {0, 2, 1},
  57. }
  58. for i := 0; i < 2; i++ {
  59. for j := 0; j < 3; j++ {
  60. got := matrix3.Element(i, j)
  61. want := expected[i][j]
  62. if want != got {
  63. t.Errorf("matrix3.Element(%d, %d) = %f,"+
  64. " want %f",
  65. i, j, got, want)
  66. }
  67. }
  68. }
  69. matrix4 := matrix2
  70. matrix4.Concat(matrix1)
  71. expected = [][]float64{
  72. {2, 0, 2},
  73. {0, 2, 2},
  74. }
  75. for i := 0; i < 2; i++ {
  76. for j := 0; j < 3; j++ {
  77. got := matrix4.Element(i, j)
  78. want := expected[i][j]
  79. if want != got {
  80. t.Errorf("matrix4.Element(%d, %d) = %f, want %f",
  81. i, j, got, want)
  82. }
  83. }
  84. }
  85. }
  86. func TestGeoMConcatSelf(t *testing.T) {
  87. m := ebiten.GeoM{}
  88. m.SetElement(0, 0, 1)
  89. m.SetElement(0, 1, 2)
  90. m.SetElement(0, 2, 3)
  91. m.SetElement(1, 0, 4)
  92. m.SetElement(1, 1, 5)
  93. m.SetElement(1, 2, 6)
  94. m.Concat(m)
  95. expected := [][]float64{
  96. {9, 12, 18},
  97. {24, 33, 48},
  98. }
  99. for i := 0; i < 2; i++ {
  100. for j := 0; j < 3; j++ {
  101. got := m.Element(i, j)
  102. want := expected[i][j]
  103. if want != got {
  104. t.Errorf("m.Element(%d, %d) = %f, want %f",
  105. i, j, got, want)
  106. }
  107. }
  108. }
  109. }
  110. func geoMToString(g ebiten.GeoM) string {
  111. a := g.Element(0, 0)
  112. b := g.Element(0, 1)
  113. c := g.Element(1, 0)
  114. d := g.Element(1, 1)
  115. tx := g.Element(0, 2)
  116. ty := g.Element(1, 2)
  117. return fmt.Sprintf("{a: %f, b: %f, c: %f, d: %f, tx: %f, ty: %f}", a, b, c, d, tx, ty)
  118. }
  119. func TestGeoMApply(t *testing.T) {
  120. trans := ebiten.GeoM{}
  121. trans.Translate(1, 2)
  122. scale := ebiten.GeoM{}
  123. scale.Scale(1.5, 2.5)
  124. cpx := ebiten.GeoM{}
  125. cpx.Rotate(math.Pi)
  126. cpx.Scale(1.5, 2.5)
  127. cpx.Translate(-2, -3)
  128. cases := []struct {
  129. GeoM ebiten.GeoM
  130. InX float64
  131. InY float64
  132. OutX float64
  133. OutY float64
  134. }{
  135. {
  136. GeoM: ebiten.GeoM{},
  137. InX: 3.14159,
  138. InY: 2.81828,
  139. OutX: 3.14159,
  140. OutY: 2.81828,
  141. },
  142. {
  143. GeoM: trans,
  144. InX: 3.14159,
  145. InY: 2.81828,
  146. OutX: 4.14159,
  147. OutY: 4.81828,
  148. },
  149. {
  150. GeoM: scale,
  151. InX: 3.14159,
  152. InY: 2.81828,
  153. OutX: 4.71239,
  154. OutY: 7.04570,
  155. },
  156. {
  157. GeoM: cpx,
  158. InX: 3.14159,
  159. InY: 2.81828,
  160. OutX: -6.71239,
  161. OutY: -10.04570,
  162. },
  163. }
  164. const delta = 0.00001
  165. for _, c := range cases {
  166. rx, ry := c.GeoM.Apply(c.InX, c.InY)
  167. if math.Abs(rx-c.OutX) > delta || math.Abs(ry-c.OutY) > delta {
  168. t.Errorf("%s.Apply(%f, %f) = (%f, %f), want (%f, %f)", geoMToString(c.GeoM), c.InX, c.InY, rx, ry, c.OutX, c.OutY)
  169. }
  170. }
  171. }
  172. func TestGeoMIsInvert(t *testing.T) {
  173. zero := ebiten.GeoM{}
  174. zero.Scale(0, 0)
  175. trans := ebiten.GeoM{}
  176. trans.Translate(1, 2)
  177. scale := ebiten.GeoM{}
  178. scale.Scale(1.5, 2.5)
  179. cpx := ebiten.GeoM{}
  180. cpx.Rotate(math.Pi)
  181. cpx.Scale(1.5, 2.5)
  182. cpx.Translate(-2, -3)
  183. cpx2 := ebiten.GeoM{}
  184. cpx2.Scale(2, 3)
  185. cpx2.Rotate(0.234)
  186. cpx2.Translate(100, 100)
  187. skew := ebiten.GeoM{}
  188. skew.Skew(1, 1)
  189. cases := []struct {
  190. GeoM ebiten.GeoM
  191. Invertible bool
  192. }{
  193. {
  194. GeoM: zero,
  195. Invertible: false,
  196. },
  197. {
  198. GeoM: ebiten.GeoM{},
  199. Invertible: true,
  200. },
  201. {
  202. GeoM: trans,
  203. Invertible: true,
  204. },
  205. {
  206. GeoM: scale,
  207. Invertible: true,
  208. },
  209. {
  210. GeoM: cpx,
  211. Invertible: true,
  212. },
  213. {
  214. GeoM: cpx2,
  215. Invertible: true,
  216. },
  217. {
  218. GeoM: skew,
  219. Invertible: true,
  220. },
  221. }
  222. pts := []struct {
  223. X float64
  224. Y float64
  225. }{
  226. {
  227. X: 0,
  228. Y: 0,
  229. },
  230. {
  231. X: 1,
  232. Y: 1,
  233. },
  234. {
  235. X: 3.14159,
  236. Y: 2.81828,
  237. },
  238. {
  239. X: -1000,
  240. Y: 1000,
  241. },
  242. }
  243. const delta = 0.001
  244. for _, c := range cases {
  245. if c.GeoM.IsInvertible() != c.Invertible {
  246. t.Errorf("%s.IsInvertible(): got: %t, want: %t", geoMToString(c.GeoM), c.GeoM.IsInvertible(), c.Invertible)
  247. }
  248. if !c.GeoM.IsInvertible() {
  249. continue
  250. }
  251. invGeoM := c.GeoM
  252. invGeoM.Invert()
  253. for _, p := range pts {
  254. x, y := p.X, p.Y
  255. gotX, gotY := invGeoM.Apply(c.GeoM.Apply(x, y))
  256. if math.Abs(gotX-x) > delta || math.Abs(gotY-y) > delta {
  257. 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)
  258. }
  259. }
  260. }
  261. }
  262. func newGeoM(a, b, c, d, tx, ty float64) ebiten.GeoM {
  263. outp := ebiten.GeoM{}
  264. outp.SetElement(0, 0, a)
  265. outp.SetElement(0, 1, b)
  266. outp.SetElement(0, 2, tx)
  267. outp.SetElement(1, 0, c)
  268. outp.SetElement(1, 1, d)
  269. outp.SetElement(1, 2, ty)
  270. return outp
  271. }
  272. func TestGeomSkew(t *testing.T) {
  273. testSkew := func(skewX, skewY float64, input, expected ebiten.GeoM) {
  274. input.Skew(skewX, skewY)
  275. for i := 0; i < 2; i++ {
  276. for j := 0; j < 3; j++ {
  277. got := input.Element(i, j)
  278. want := expected.Element(i, j)
  279. if want != got {
  280. t.Errorf("Skew(%f, %f): got %s, want: %s", skewX, skewY, input.String(), expected.String())
  281. return
  282. }
  283. }
  284. }
  285. }
  286. // skewX = 0.25
  287. expectedX := newGeoM(1, math.Tan(0.25), math.Tan(0), 1, 0, 0)
  288. testSkew(0.25, 0, ebiten.GeoM{}, expectedX)
  289. // skewY = 0.25
  290. expectedY := newGeoM(1, math.Tan(0), math.Tan(0.5), 1, 0, 0)
  291. testSkew(0, 0.5, ebiten.GeoM{}, expectedY)
  292. // skewX, skewY = 0.3, 0.8
  293. expectedXY := newGeoM(1, math.Tan(0.3), math.Tan(0.8), 1, 0, 0)
  294. testSkew(0.3, 0.8, ebiten.GeoM{}, expectedXY)
  295. // skewX, skewY = 0.4, -1.8 ; b, c = 2, 3
  296. 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)
  297. inputOffDiag := newGeoM(1, 2, 3, 1, 0, 0)
  298. testSkew(0.4, -1.8, inputOffDiag, expectedOffDiag)
  299. // skewX, skewY = -1.5, 1.5 ; tx, ty = 5, 6
  300. expectedTrn := newGeoM(1, math.Tan(-1.5), math.Tan(1.5), 1, 5+math.Tan(-1.5)*6, 6+5*math.Tan(1.5))
  301. inputTrn := newGeoM(1, 0, 0, 1, 5, 6)
  302. testSkew(-1.5, 1.5, inputTrn, expectedTrn)
  303. }
  304. func TestGeoMEquals(t *testing.T) {
  305. tests := []struct {
  306. a ebiten.GeoM
  307. b ebiten.GeoM
  308. want bool
  309. }{
  310. {
  311. a: ebiten.GeoM{},
  312. b: ebiten.GeoM{},
  313. want: true,
  314. },
  315. {
  316. a: newGeoM(3, 1, 4, 1, 5, 9),
  317. b: newGeoM(3, 1, 4, 1, 5, 9),
  318. want: true,
  319. },
  320. {
  321. a: newGeoM(3, 1, 4, 1, 5, 9),
  322. b: newGeoM(3, 1, 4, 1, 5, 10),
  323. want: false,
  324. },
  325. }
  326. for _, test := range tests {
  327. got := (test.a == test.b)
  328. want := test.want
  329. if got != want {
  330. t.Errorf("%#v == %#v: got %t, want: %t", test.a, test.b, got, want)
  331. }
  332. }
  333. }
  334. func BenchmarkGeoM(b *testing.B) {
  335. var m ebiten.GeoM
  336. for i := 0; i < b.N; i++ {
  337. m = ebiten.GeoM{}
  338. m.Translate(10, 20)
  339. m.Scale(2, 3)
  340. m.Rotate(math.Pi / 2)
  341. }
  342. }