2D Vector Library
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

vector_test.go 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852
  1. package vector
  2. import (
  3. "errors"
  4. "math"
  5. "testing"
  6. )
  7. func TestSubMag(t *testing.T) {
  8. p1 := Point2d{10, 10}
  9. p2 := Point2d{7, 6}
  10. v := p1.Sub(p2)
  11. if v != (Vector2d{3, 4}) {
  12. t.Errorf("Sub Error")
  13. }
  14. m := v.Mag()
  15. if m != 5 {
  16. t.Errorf("Mag Error")
  17. }
  18. }
  19. func TestScale(t *testing.T) {
  20. v := Vector2d{3, 4}
  21. m := v.Mag()
  22. if m != 5 {
  23. t.Errorf("Mag Error")
  24. }
  25. m2 := v.Scale(2)
  26. if m2.Mag() != 10 {
  27. t.Errorf("Mag Error")
  28. }
  29. }
  30. func TestAdd(t *testing.T) {
  31. p := Point2d{10, 10}
  32. v := Vector2d{3, 4}
  33. m := p.Add(v)
  34. if m.X != 13 && m.Y != 14 {
  35. t.Errorf("Add Error")
  36. }
  37. }
  38. func TestNormalize(t *testing.T) {
  39. v := Vector2d{3, 4}
  40. vn := v.Normalize()
  41. if vn.Mag() != 1 {
  42. t.Errorf("Normalize Error")
  43. }
  44. v0 := Vector2d{0, 0}
  45. vn0 := v0.Normalize()
  46. if vn0.Mag() != 0 {
  47. t.Errorf("Normalize Error")
  48. }
  49. }
  50. func TestDot(t *testing.T) {
  51. v1 := Vector2d{0, 5}
  52. v2 := Vector2d{5, 0}
  53. d := v1.Dot(v2)
  54. if d != 0 {
  55. t.Errorf("Dot Error")
  56. }
  57. v1 = Vector2d{1, 5}
  58. v2 = Vector2d{5, 0}
  59. d = v1.Dot(v2)
  60. if d < 0 {
  61. t.Errorf("Dot Error")
  62. }
  63. v1 = Vector2d{-1, 5}
  64. v2 = Vector2d{5, 0}
  65. d = v1.Dot(v2)
  66. if d > 0 {
  67. t.Errorf("Dot Error")
  68. }
  69. v1 = Vector2d{5, 5}
  70. v2 = Vector2d{5, 0}
  71. v1 = v1.Normalize()
  72. v2 = v2.Normalize()
  73. d = v1.Dot(v2)
  74. if math.Abs(float64(d)-math.Acos(math.Pi/4)) < 0.0001 {
  75. t.Errorf("Dot Error")
  76. }
  77. }
  78. func TestIntersection(t *testing.T) {
  79. p1 := Point2d{0, 5}
  80. p2 := Point2d{5, 0}
  81. v1 := Vector2d{10, 0}
  82. v2 := Vector2d{0, 10}
  83. i, _ := Intersection(p1, p2, v1, v2)
  84. if !i {
  85. t.Errorf("Intersection Error")
  86. }
  87. p1 = Point2d{20, 5}
  88. p2 = Point2d{5, 0}
  89. v1 = Vector2d{10, 0}
  90. v2 = Vector2d{0, 10}
  91. i, _ = Intersection(p1, p2, v1, v2)
  92. if i {
  93. t.Errorf("Intersection Error")
  94. }
  95. }
  96. func TestAngle(t *testing.T) {
  97. cases := []struct {
  98. v1 Vector2d
  99. v2 Vector2d
  100. expected float64
  101. }{
  102. {
  103. v1: Vector2d{10, 0},
  104. v2: Vector2d{0, 10},
  105. expected: -math.Pi / 2,
  106. },
  107. {
  108. v1: Vector2d{5, 0},
  109. v2: Vector2d{10, 10},
  110. expected: -math.Pi / 4,
  111. },
  112. {
  113. v1: Vector2d{0, 10},
  114. v2: Vector2d{0, -10},
  115. expected: math.Pi,
  116. },
  117. // nan angles:
  118. {
  119. v1: Vector2d{0, 0},
  120. v2: Vector2d{0, 0},
  121. expected: 0,
  122. },
  123. // nan angles
  124. {
  125. v1: Vector2d{0.0001, 0},
  126. v2: Vector2d{0, 0},
  127. expected: math.Pi * Rad2deg,
  128. },
  129. }
  130. var a float64
  131. for _, c := range cases {
  132. a = Angle(c.v2, c.v1)
  133. if math.Abs(float64(a-c.expected)) > Epsilon {
  134. t.Errorf("Angle Error; expected: %f, actual: %f", c.expected, a)
  135. }
  136. }
  137. }
  138. func TestRotate(t *testing.T) {
  139. v1 := Vector2d{10, 0}
  140. v2 := v1.Rotate(math.Pi / 2)
  141. if v2.X > Epsilon || v2.Y-10 > Epsilon {
  142. t.Errorf("Rotate Error")
  143. }
  144. v1 = Vector2d{1, 0}
  145. v2 = v1.Rotate(-30 * Deg2rad)
  146. if v2.X-0.866025403784438 > Epsilon || v2.Y+0.5 > Epsilon {
  147. t.Errorf("Rotate Error")
  148. }
  149. }
  150. func TestPtInRect(t *testing.T) {
  151. p1 := Point2d{10, 0}
  152. p2 := Point2d{10, 10}
  153. p3 := Point2d{11, 10000}
  154. p4 := Point2d{0, 0}
  155. pA := Point2d{5, 5}
  156. pB := Point2d{15, 15}
  157. r := AABB2d{
  158. A: pA,
  159. B: pB,
  160. }
  161. out := PointInRect(p1, r)
  162. if out != false {
  163. t.Errorf("PointInRect Error")
  164. }
  165. out = PointInRect(p2, r)
  166. if out != true {
  167. t.Errorf("PointInRect Error")
  168. }
  169. out = PointInRect(p3, r)
  170. if out != false {
  171. t.Errorf("PointInRect Error")
  172. }
  173. out = PointInRect(p4, r)
  174. if out != false {
  175. t.Errorf("PointInRect Error")
  176. }
  177. }
  178. func TestRectIntersect(t *testing.T) {
  179. type result struct {
  180. collided bool
  181. inside bool
  182. pos *Point2d
  183. }
  184. tests := []struct {
  185. rect AABB2d
  186. p Point2d
  187. v Vector2d
  188. expected result
  189. }{
  190. // inside
  191. {
  192. rect: AABB2d{
  193. A: Point2d{0, 0},
  194. B: Point2d{10, 10},
  195. },
  196. p: Point2d{1, 1},
  197. v: Vector2d{2, 2},
  198. expected: result{
  199. collided: false,
  200. inside: true,
  201. pos: nil,
  202. },
  203. },
  204. // bottom
  205. {
  206. rect: AABB2d{
  207. A: Point2d{5, 5},
  208. B: Point2d{15, 15},
  209. },
  210. p: Point2d{10, 0},
  211. v: Vector2d{0, 10},
  212. expected: result{
  213. collided: true,
  214. inside: false,
  215. pos: &Point2d{10, 5},
  216. },
  217. },
  218. // wall left
  219. {
  220. rect: AABB2d{
  221. A: Point2d{0, 0},
  222. B: Point2d{10, 10},
  223. },
  224. p: Point2d{-1, 5},
  225. v: Vector2d{2, 0},
  226. expected: result{
  227. collided: true,
  228. inside: false,
  229. pos: &Point2d{0, 5},
  230. },
  231. },
  232. // wall right
  233. {
  234. rect: AABB2d{
  235. A: Point2d{0, 0},
  236. B: Point2d{10, 10},
  237. },
  238. p: Point2d{11, 5},
  239. v: Vector2d{-2, 0},
  240. expected: result{
  241. collided: true,
  242. inside: false,
  243. pos: &Point2d{10, 5},
  244. },
  245. },
  246. // wall top
  247. {
  248. rect: AABB2d{
  249. A: Point2d{0, 0},
  250. B: Point2d{10, 10},
  251. },
  252. p: Point2d{5, 11},
  253. v: Vector2d{0, -2},
  254. expected: result{
  255. collided: true,
  256. inside: false,
  257. pos: &Point2d{5, 10},
  258. },
  259. },
  260. // outside
  261. {
  262. rect: AABB2d{
  263. A: Point2d{0, 0},
  264. B: Point2d{10, 10},
  265. },
  266. p: Point2d{5, -1},
  267. v: Vector2d{0, -1},
  268. expected: result{
  269. collided: false,
  270. inside: false,
  271. pos: nil,
  272. },
  273. },
  274. }
  275. for _, test := range tests {
  276. coll, inside, pos := RectIntersection(test.rect, test.p, test.v)
  277. if coll != test.expected.collided {
  278. t.Errorf("unexpected collision: expected: %t, actual: %t", test.expected.collided, coll)
  279. }
  280. if inside != test.expected.inside {
  281. t.Errorf("RectIntersection Error")
  282. t.Errorf("unexpected inside: expected: %t, actual: %t", test.expected.inside, inside)
  283. }
  284. if test.expected.pos == nil && pos != nil {
  285. t.Error("expected nil position, got non-nil")
  286. }
  287. if pos != nil && test.expected.pos != nil {
  288. if *pos != *test.expected.pos {
  289. t.Errorf("unexpected collision point: expected: %+v, actual: %+v", test.expected.pos, pos)
  290. }
  291. }
  292. }
  293. }
  294. func TestRectRectIntersectionTrue(t *testing.T) {
  295. r1 := AABB2d{Point2d{10, 10}, Point2d{20, 20}}
  296. r2 := AABB2d{Point2d{15, 15}, Point2d{25, 25}}
  297. col := RectRectIntersection(r1, r2)
  298. if !col {
  299. t.Errorf("RectRect Error")
  300. }
  301. r1 = AABB2d{Point2d{10, 10}, Point2d{20, 20}}
  302. r2 = AABB2d{Point2d{5, 15}, Point2d{30, 25}}
  303. col = RectRectIntersection(r1, r2)
  304. if !col {
  305. t.Errorf("RectRect Error")
  306. }
  307. }
  308. func TestRectRectIntersectionFalse(t *testing.T) {
  309. r1 := AABB2d{Point2d{10, 10}, Point2d{14, 14}}
  310. r2 := AABB2d{Point2d{15, 15}, Point2d{25, 25}}
  311. col := RectRectIntersection(r1, r2)
  312. if col {
  313. t.Errorf("RectRect Error")
  314. }
  315. }
  316. func TestPolyIntersect(t *testing.T) {
  317. p1 := Polygon2d{}
  318. p1.Points = append(p1.Points, Vector2d{3, 3})
  319. p1.Points = append(p1.Points, Vector2d{5, 5})
  320. p1.Points = append(p1.Points, Vector2d{5, 3})
  321. i, _ := PolygonIntersection(p1, Point2d{0, 0}, Vector2d{10, 10})
  322. if i {
  323. t.Errorf("PolyIntersect Error")
  324. }
  325. }
  326. func TestPolyIntersectFail(t *testing.T) {
  327. p1 := Polygon2d{}
  328. p1.Points = append(p1.Points, Vector2d{3, 3})
  329. p1.Points = append(p1.Points, Vector2d{5, 5})
  330. p1.Points = append(p1.Points, Vector2d{5, 3})
  331. i, _ := PolygonIntersection(p1, Point2d{0, 0}, Vector2d{-10, -10})
  332. if i {
  333. t.Errorf("PolyIntersect Error")
  334. }
  335. }
  336. func TestPolyIntersectTwoHits(t *testing.T) {
  337. p1 := Polygon2d{}
  338. p1.Points = append(p1.Points, Vector2d{0, 0})
  339. p1.Points = append(p1.Points, Vector2d{0, 10})
  340. p1.Points = append(p1.Points, Vector2d{10, 10})
  341. p1.Points = append(p1.Points, Vector2d{10, 0})
  342. i, p := PolygonIntersection(p1, Point2d{-1, 5}, Vector2d{20, 0})
  343. if !i || (p.X != 0 && p.Y != 5) {
  344. t.Errorf("PolyIntersect Error")
  345. }
  346. }
  347. func TestPolyPolyIntersect(t *testing.T) {
  348. p1 := Polygon2d{}
  349. p1.Points = append(p1.Points, Vector2d{0, 0})
  350. p1.Points = append(p1.Points, Vector2d{0, 10})
  351. p1.Points = append(p1.Points, Vector2d{10, 10})
  352. p1.Points = append(p1.Points, Vector2d{10, 0})
  353. p2 := Polygon2d{}
  354. p2.Origin = Point2d{5, 5}
  355. p2.Points = append(p2.Points, Vector2d{0, 0})
  356. p2.Points = append(p2.Points, Vector2d{0, 10})
  357. p2.Points = append(p2.Points, Vector2d{10, 10})
  358. p2.Points = append(p2.Points, Vector2d{10, 0})
  359. i, _, _ := PolyPolyIntersection(p1, Vector2d{0, 0}, p2)
  360. if !i {
  361. t.Errorf("should have intersected")
  362. }
  363. }
  364. func TestPolyPolyIntersectNegativeTranslationScale(t *testing.T) {
  365. p1 := Polygon2d{}
  366. p1.Points = append(p1.Points, Vector2d{0, 0})
  367. p1.Points = append(p1.Points, Vector2d{0, 10})
  368. p1.Points = append(p1.Points, Vector2d{10, 10})
  369. p1.Points = append(p1.Points, Vector2d{10, 0})
  370. p2 := Polygon2d{}
  371. p2.Origin = Point2d{-5, -5}
  372. p2.Points = append(p2.Points, Vector2d{0, 0})
  373. p2.Points = append(p2.Points, Vector2d{0, 10})
  374. p2.Points = append(p2.Points, Vector2d{10, 10})
  375. p2.Points = append(p2.Points, Vector2d{10, 0})
  376. i, _, _ := PolyPolyIntersection(p1, Vector2d{0, 0}, p2)
  377. if !i {
  378. t.Errorf("should not have intersected")
  379. }
  380. }
  381. func TestPolyPolyIntersectMoving(t *testing.T) {
  382. p1 := Polygon2d{}
  383. p1.Points = append(p1.Points, Vector2d{0, 0})
  384. p1.Points = append(p1.Points, Vector2d{0, 10})
  385. p1.Points = append(p1.Points, Vector2d{10, 10})
  386. p1.Points = append(p1.Points, Vector2d{10, 0})
  387. p2 := Polygon2d{}
  388. p2.Origin = Point2d{15, 15}
  389. p2.Points = append(p2.Points, Vector2d{0, 0})
  390. p2.Points = append(p2.Points, Vector2d{0, 10})
  391. p2.Points = append(p2.Points, Vector2d{10, 10})
  392. p2.Points = append(p2.Points, Vector2d{10, 0})
  393. i, m, _ := PolyPolyIntersection(p1, Vector2d{10, 10}, p2)
  394. if i {
  395. t.Errorf("should not have started intersected")
  396. }
  397. if !m {
  398. t.Errorf("should have intersected after movement")
  399. }
  400. }
  401. func TestPolyPolyIntersectFail(t *testing.T) {
  402. p1 := Polygon2d{}
  403. p1.Points = append(p1.Points, Vector2d{0, 0})
  404. p1.Points = append(p1.Points, Vector2d{0, 10})
  405. p1.Points = append(p1.Points, Vector2d{10, 10})
  406. p1.Points = append(p1.Points, Vector2d{10, 0})
  407. p2 := Polygon2d{}
  408. p2.Origin = Point2d{15, 15}
  409. p2.Points = append(p2.Points, Vector2d{0, 0})
  410. p2.Points = append(p2.Points, Vector2d{0, 10})
  411. p2.Points = append(p2.Points, Vector2d{10, 10})
  412. p2.Points = append(p2.Points, Vector2d{10, 0})
  413. i, m, _ := PolyPolyIntersection(p1, Vector2d{0, 0}, p2)
  414. if i || m {
  415. t.Errorf("should not have intersected")
  416. }
  417. }
  418. func TestPolyPolyNoOverlapMoveOnto(t *testing.T) {
  419. p1 := Polygon2d{}
  420. p1.Points = append(p1.Points, Vector2d{0, 0})
  421. p1.Points = append(p1.Points, Vector2d{0, 10})
  422. p1.Points = append(p1.Points, Vector2d{10, 10})
  423. p1.Points = append(p1.Points, Vector2d{10, 0})
  424. p2 := Polygon2d{}
  425. p2.Origin = Point2d{15, 15}
  426. p2.Points = append(p2.Points, Vector2d{0, 0})
  427. p2.Points = append(p2.Points, Vector2d{0, 10})
  428. p2.Points = append(p2.Points, Vector2d{10, 10})
  429. p2.Points = append(p2.Points, Vector2d{10, 0})
  430. i, m, _ := PolyPolyIntersection(p1, Vector2d{-10, -10}, p2)
  431. if i {
  432. t.Errorf("should not have started intersecting")
  433. }
  434. if m {
  435. t.Errorf("should not have intersected")
  436. }
  437. }
  438. func TestOrientedSquare(t *testing.T) {
  439. p := OrientedSquare(Point2d{10, 10}, Vector2d{0.5, 0.5}, 5)
  440. expected := []Vector2d{
  441. {X: 0, Y: 7.071067811865475},
  442. {X: -7.071067811865475, Y: 0},
  443. {X: 0, Y: -7.071067811865475},
  444. {X: 7.071067811865475, Y: 0},
  445. }
  446. for i, v := range expected {
  447. if p.Points[i] != v {
  448. t.Errorf("unexpected points: %+v, expected: %+v", p.Points, expected)
  449. }
  450. }
  451. }
  452. func TestPopPop(t *testing.T) {
  453. v1 := Vector2d{10, 10}
  454. if v1.PopPop() != math.Sqrt(10*10+10*10) {
  455. t.Errorf("Incorrect Magnitude!")
  456. }
  457. }
  458. func TestAASquareAtPoint(t *testing.T) {
  459. p1 := Point2d{10, 10}
  460. expected := AABB2d{
  461. A: Point2d{5, 5},
  462. B: Point2d{15, 15},
  463. }
  464. aabb := AASquareAtPoint(p1, 10)
  465. if aabb != expected {
  466. t.Errorf("incorrect AABB2d; expected: %+v, calculated: %+v ", expected, aabb)
  467. }
  468. }
  469. func TestDistance(t *testing.T) {
  470. if Distance(Point2d{0, 0}, Point2d{0, 0}) != 0.0 {
  471. t.Error("incorectly calculating distance between two points at origin")
  472. }
  473. if Distance(Point2d{0, 0}, Point2d{10, 0}) != 10.0 {
  474. t.Error("incorectly calculating distance between points on y axis")
  475. }
  476. if Distance(Point2d{0, 0}, Point2d{3, 4}) != 5.0 {
  477. t.Error("incorectly calculating distance for pythagorean triple")
  478. }
  479. }
  480. func TestAABBToRect(t *testing.T) {
  481. r := AABB2d{
  482. A: Point2d{5, 5},
  483. B: Point2d{15, 15},
  484. }
  485. p := r.ToPolygon()
  486. expected := Polygon2d{
  487. Points: []Vector2d{
  488. Vector2d{X: 0, Y: 0},
  489. Vector2d{X: 0, Y: 10},
  490. Vector2d{X: 10, Y: 10},
  491. Vector2d{X: 10, Y: 0},
  492. },
  493. Origin: Point2d{X: 5, Y: 5},
  494. }
  495. if len(p.Points) != 4 {
  496. t.Error("incorrect number of points")
  497. }
  498. // alright, this just feels cumbersome ... unfortunate that structs with
  499. // slices can't be compared this way ...
  500. if p.Origin != expected.Origin {
  501. t.Error("just wrong")
  502. }
  503. for i, pp := range expected.Points {
  504. if p.Points[i] != pp {
  505. t.Error("just wrong")
  506. }
  507. }
  508. }
  509. func TestPointInPolygon(t *testing.T) {
  510. poly := AABB2d{
  511. A: Point2d{5, 5},
  512. B: Point2d{15, 15},
  513. }.ToPolygon()
  514. point := Point2d{10, 10}
  515. if success := PointInPolygon(point, poly); !success {
  516. // XXX: this needs removed ;)
  517. t.Skip("NYI")
  518. t.Error("point should have been in polygon")
  519. }
  520. }
  521. func TestExtrapolate(t *testing.T) {
  522. _, err := Extrapolate([]Point2d{})
  523. if err == nil {
  524. t.Error("should require len(P) == 3")
  525. }
  526. tests := []struct {
  527. points []Point2d
  528. expected Point2d
  529. }{
  530. {
  531. points: []Point2d{
  532. {0, 0},
  533. {1, 1},
  534. {2, 2},
  535. },
  536. expected: Point2d{3, 3},
  537. },
  538. {
  539. points: []Point2d{
  540. {0, 0},
  541. {1, 1},
  542. {2, 1},
  543. },
  544. expected: Point2d{3, 0},
  545. },
  546. {
  547. points: []Point2d{
  548. {0, 0},
  549. {1, 0},
  550. {2, 0},
  551. },
  552. expected: Point2d{3, 0},
  553. },
  554. {
  555. points: []Point2d{
  556. {0, 0},
  557. {0, 1},
  558. {0, 2},
  559. },
  560. expected: Point2d{0, 3},
  561. },
  562. {
  563. points: []Point2d{
  564. {0, 0},
  565. {0, 0},
  566. {0, 0},
  567. },
  568. expected: Point2d{0, 0},
  569. },
  570. {
  571. points: []Point2d{
  572. {42, 42},
  573. {42, 42},
  574. {42, 42},
  575. },
  576. expected: Point2d{42, 42},
  577. },
  578. {
  579. points: []Point2d{
  580. {104, 288},
  581. {110, 270},
  582. {120, 250},
  583. },
  584. expected: Point2d{134, 228},
  585. },
  586. {
  587. points: []Point2d{
  588. {0, 0},
  589. {5, 3},
  590. {7, 3},
  591. },
  592. expected: Point2d{6, 0},
  593. },
  594. }
  595. for _, test := range tests {
  596. p, err := Extrapolate(test.points)
  597. if err != nil {
  598. t.Errorf("yeah, this should've been nil: %s", err)
  599. }
  600. if *p != test.expected {
  601. t.Errorf("wrong: expected: %+v, actual: %+v", test.expected, p)
  602. }
  603. }
  604. }
  605. func TestNeville(t *testing.T) {
  606. knownFails := []struct {
  607. points []Point2d
  608. ts []float64
  609. t float64
  610. expected Point2d
  611. err error
  612. }{
  613. {
  614. points: []Point2d{
  615. {0, 0},
  616. {1, 1},
  617. {2, 2},
  618. },
  619. ts: []float64{
  620. 1.0 / 3.0,
  621. 2.0 / 3.0,
  622. },
  623. err: errors.New("Incompatable slice lengths len(P): 3 != len(ts): 2"),
  624. },
  625. }
  626. for _, test := range knownFails {
  627. p, err := Neville(test.points, test.ts, test.t)
  628. if p != nil {
  629. t.Errorf("p should've been nil: %+v", p)
  630. }
  631. if err.Error() != test.err.Error() {
  632. t.Errorf("expected err: '%s', unexpectd err: '%s'", test.err, err)
  633. }
  634. }
  635. tests := []struct {
  636. points []Point2d
  637. ts []float64
  638. t float64
  639. expected Point2d
  640. }{
  641. {
  642. points: []Point2d{
  643. {0, 0},
  644. {3, 3},
  645. {5, 3},
  646. {7, 0},
  647. },
  648. ts: []float64{
  649. 0,
  650. 1,
  651. 3,
  652. 4,
  653. },
  654. t: 2.0,
  655. expected: Point2d{25.0 / 6.0, 4.0},
  656. },
  657. {
  658. points: []Point2d{
  659. {0, 0},
  660. {1, 1},
  661. {2, 2},
  662. },
  663. ts: []float64{
  664. 0,
  665. 1.0 / 3.0,
  666. 2.0 / 3.0,
  667. },
  668. t: 1.0,
  669. expected: Point2d{3, 3},
  670. },
  671. {
  672. points: []Point2d{
  673. {0, 0},
  674. {1, 1},
  675. {2, 1},
  676. },
  677. ts: []float64{
  678. 0,
  679. 1.0 / 3.0,
  680. 2.0 / 3.0,
  681. },
  682. t: 1.0,
  683. expected: Point2d{3, 0},
  684. },
  685. {
  686. ts: []float64{
  687. 0,
  688. 1.0 / 3.0,
  689. 2.0 / 3.0,
  690. },
  691. t: 1.0,
  692. points: []Point2d{
  693. {0, 0},
  694. {1, 0},
  695. {2, 0},
  696. },
  697. expected: Point2d{3, 0},
  698. },
  699. {
  700. points: []Point2d{
  701. {0, 0},
  702. {0, 1},
  703. {0, 2},
  704. },
  705. ts: []float64{
  706. 0,
  707. 1.0 / 3.0,
  708. 2.0 / 3.0,
  709. },
  710. t: 1.0,
  711. expected: Point2d{0, 3},
  712. },
  713. {
  714. ts: []float64{
  715. 0,
  716. 1.0 / 3.0,
  717. 2.0 / 3.0,
  718. },
  719. t: 1.0,
  720. points: []Point2d{
  721. {0, 0},
  722. {0, 0},
  723. {0, 0},
  724. },
  725. expected: Point2d{0, 0},
  726. },
  727. {
  728. points: []Point2d{
  729. {42, 42},
  730. {42, 42},
  731. {42, 42},
  732. },
  733. expected: Point2d{42, 42},
  734. ts: []float64{
  735. 0,
  736. 1.0 / 3.0,
  737. 2.0 / 3.0,
  738. },
  739. t: 1.0,
  740. },
  741. {
  742. points: []Point2d{
  743. {104, 288},
  744. {110, 270},
  745. {120, 250},
  746. },
  747. expected: Point2d{134, 228},
  748. ts: []float64{
  749. 0,
  750. 1.0 / 3.0,
  751. 2.0 / 3.0,
  752. },
  753. t: 1.0,
  754. },
  755. }
  756. for _, test := range tests {
  757. p, err := Neville(test.points, test.ts, test.t)
  758. if err != nil {
  759. t.Errorf("yeah, this should've been nil: %s", err)
  760. }
  761. if p == nil {
  762. t.Errorf("nil point?")
  763. } else {
  764. deltaX := math.Abs(float64(p.X - test.expected.X))
  765. deltaY := math.Abs(float64(p.Y - test.expected.Y))
  766. if deltaX > 1e-4 || deltaY > 1e-4 { // HOLY SHIT!!!
  767. t.Errorf("wrong: expected: %+v, actual: %+v", test.expected, p)
  768. }
  769. }
  770. }
  771. }