path_test.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  1. // Copyright 2008 The Closure Library Authors. All Rights Reserved.
  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. goog.provide('goog.math.PathTest');
  15. goog.require('goog.array');
  16. goog.require('goog.math.AffineTransform');
  17. goog.require('goog.math.Path');
  18. goog.require('goog.testing.jsunit');
  19. goog.setTestOnly('goog.math.PathTest');
  20. /**
  21. * Array mapping numeric segment constant to a descriptive character.
  22. * @type {!Array<string>}
  23. * @private
  24. */
  25. var SEGMENT_NAMES_ = function() {
  26. var arr = [];
  27. arr[goog.math.Path.Segment.MOVETO] = 'M';
  28. arr[goog.math.Path.Segment.LINETO] = 'L';
  29. arr[goog.math.Path.Segment.CURVETO] = 'C';
  30. arr[goog.math.Path.Segment.ARCTO] = 'A';
  31. arr[goog.math.Path.Segment.CLOSE] = 'X';
  32. return arr;
  33. }();
  34. /**
  35. * Test if the given path matches the expected array of commands and parameters.
  36. * @param {Array<string|number>} expected The expected array of commands and
  37. * parameters.
  38. * @param {goog.math.Path} path The path to test against.
  39. */
  40. var assertPathEquals = function(expected, path) {
  41. var actual = [];
  42. path.forEachSegment(function(seg, args) {
  43. actual.push(SEGMENT_NAMES_[seg]);
  44. Array.prototype.push.apply(actual, args);
  45. });
  46. assertEquals(expected.length, actual.length);
  47. for (var i = 0; i < expected.length; i++) {
  48. if (goog.isNumber(expected[i])) {
  49. assertTrue(goog.isNumber(actual[i]));
  50. assertRoughlyEquals(expected[i], actual[i], 0.01);
  51. } else {
  52. assertEquals(expected[i], actual[i]);
  53. }
  54. }
  55. };
  56. function testConstructor() {
  57. var path = new goog.math.Path();
  58. assertTrue(path.isSimple());
  59. assertNull(path.getCurrentPoint());
  60. assertPathEquals([], path);
  61. }
  62. function testGetSegmentCount() {
  63. assertArrayEquals(
  64. [2, 2, 6, 6, 0],
  65. goog.array.map(
  66. [
  67. goog.math.Path.Segment.MOVETO, goog.math.Path.Segment.LINETO,
  68. goog.math.Path.Segment.CURVETO, goog.math.Path.Segment.ARCTO,
  69. goog.math.Path.Segment.CLOSE
  70. ],
  71. goog.math.Path.getSegmentCount));
  72. }
  73. function testSimpleMoveTo() {
  74. var path = new goog.math.Path();
  75. path.moveTo(30, 50);
  76. assertTrue(path.isSimple());
  77. assertObjectEquals([30, 50], path.getCurrentPoint());
  78. assertPathEquals(['M', 30, 50], path);
  79. }
  80. function testRepeatedMoveTo() {
  81. var path = new goog.math.Path();
  82. path.moveTo(30, 50);
  83. path.moveTo(40, 60);
  84. assertTrue(path.isSimple());
  85. assertObjectEquals([40, 60], path.getCurrentPoint());
  86. assertPathEquals(['M', 40, 60], path);
  87. }
  88. function testSimpleLineTo_fromArgs() {
  89. var path = new goog.math.Path();
  90. var e = assertThrows(function() { path.lineTo(30, 50); });
  91. assertEquals('Path cannot start with lineTo', e.message);
  92. path.moveTo(0, 0);
  93. path.lineTo(30, 50);
  94. assertTrue(path.isSimple());
  95. assertObjectEquals([30, 50], path.getCurrentPoint());
  96. assertPathEquals(['M', 0, 0, 'L', 30, 50], path);
  97. }
  98. function testSimpleLineTo_fromArray() {
  99. var path = new goog.math.Path();
  100. var e = assertThrows(function() { path.lineToFromArray([30, 50]); });
  101. assertEquals('Path cannot start with lineTo', e.message);
  102. path.moveTo(0, 0);
  103. path.lineToFromArray([30, 50]);
  104. assertTrue(path.isSimple());
  105. assertObjectEquals([30, 50], path.getCurrentPoint());
  106. assertPathEquals(['M', 0, 0, 'L', 30, 50], path);
  107. }
  108. function testMultiArgLineTo_fromArgs() {
  109. var path = new goog.math.Path();
  110. path.moveTo(0, 0);
  111. path.lineTo(30, 50, 40, 60);
  112. assertTrue(path.isSimple());
  113. assertObjectEquals([40, 60], path.getCurrentPoint());
  114. assertPathEquals(['M', 0, 0, 'L', 30, 50, 40, 60], path);
  115. }
  116. function testMultiArgLineTo_fromArray() {
  117. var path = new goog.math.Path();
  118. path.moveTo(0, 0);
  119. path.lineToFromArray([30, 50, 40, 60]);
  120. assertTrue(path.isSimple());
  121. assertObjectEquals([40, 60], path.getCurrentPoint());
  122. assertPathEquals(['M', 0, 0, 'L', 30, 50, 40, 60], path);
  123. }
  124. function testRepeatedLineTo_fromArgs() {
  125. var path = new goog.math.Path();
  126. path.moveTo(0, 0);
  127. path.lineTo(30, 50);
  128. path.lineTo(40, 60);
  129. assertTrue(path.isSimple());
  130. assertObjectEquals([40, 60], path.getCurrentPoint());
  131. assertPathEquals(['M', 0, 0, 'L', 30, 50, 40, 60], path);
  132. }
  133. function testRepeatedLineTo_fromArray() {
  134. var path = new goog.math.Path();
  135. path.moveTo(0, 0);
  136. path.lineToFromArray([30, 50]);
  137. path.lineToFromArray([40, 60]);
  138. assertTrue(path.isSimple());
  139. assertObjectEquals([40, 60], path.getCurrentPoint());
  140. assertPathEquals(['M', 0, 0, 'L', 30, 50, 40, 60], path);
  141. }
  142. function testSimpleCurveTo_fromArgs() {
  143. var path = new goog.math.Path();
  144. var e = assertThrows(function() { path.curveTo(10, 20, 30, 40, 50, 60); });
  145. assertEquals('Path cannot start with curve', e.message);
  146. path.moveTo(0, 0);
  147. path.curveTo(10, 20, 30, 40, 50, 60);
  148. assertTrue(path.isSimple());
  149. assertObjectEquals([50, 60], path.getCurrentPoint());
  150. assertPathEquals(['M', 0, 0, 'C', 10, 20, 30, 40, 50, 60], path);
  151. }
  152. function testSimpleCurveTo_fromArray() {
  153. var path = new goog.math.Path();
  154. var e = assertThrows(function() {
  155. path.curveToFromArray([10, 20, 30, 40, 50, 60]);
  156. });
  157. assertEquals('Path cannot start with curve', e.message);
  158. path.moveTo(0, 0);
  159. path.curveToFromArray([10, 20, 30, 40, 50, 60]);
  160. assertTrue(path.isSimple());
  161. assertObjectEquals([50, 60], path.getCurrentPoint());
  162. assertPathEquals(['M', 0, 0, 'C', 10, 20, 30, 40, 50, 60], path);
  163. }
  164. function testMultiCurveTo_fromArgs() {
  165. var path = new goog.math.Path();
  166. path.moveTo(0, 0);
  167. path.curveTo(10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120);
  168. assertTrue(path.isSimple());
  169. assertObjectEquals([110, 120], path.getCurrentPoint());
  170. assertPathEquals(
  171. ['M', 0, 0, 'C', 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120],
  172. path);
  173. }
  174. function testMultiCurveTo_fromArray() {
  175. var path = new goog.math.Path();
  176. path.moveTo(0, 0);
  177. path.curveToFromArray([10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120]);
  178. assertTrue(path.isSimple());
  179. assertObjectEquals([110, 120], path.getCurrentPoint());
  180. assertPathEquals(
  181. ['M', 0, 0, 'C', 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120],
  182. path);
  183. }
  184. function testRepeatedCurveTo_fromArgs() {
  185. var path = new goog.math.Path();
  186. path.moveTo(0, 0);
  187. path.curveTo(10, 20, 30, 40, 50, 60);
  188. path.curveTo(70, 80, 90, 100, 110, 120);
  189. assertTrue(path.isSimple());
  190. assertObjectEquals([110, 120], path.getCurrentPoint());
  191. assertPathEquals(
  192. ['M', 0, 0, 'C', 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120],
  193. path);
  194. }
  195. function testRepeatedCurveTo_fromArray() {
  196. var path = new goog.math.Path();
  197. path.moveTo(0, 0);
  198. path.curveToFromArray([10, 20, 30, 40, 50, 60]);
  199. path.curveToFromArray([70, 80, 90, 100, 110, 120]);
  200. assertTrue(path.isSimple());
  201. assertObjectEquals([110, 120], path.getCurrentPoint());
  202. assertPathEquals(
  203. ['M', 0, 0, 'C', 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120],
  204. path);
  205. }
  206. function testSimpleArc() {
  207. var path = new goog.math.Path();
  208. path.arc(50, 60, 10, 20, 30, 30, false);
  209. assertFalse(path.isSimple());
  210. var p = path.getCurrentPoint();
  211. assertEquals(55, p[0]);
  212. assertRoughlyEquals(77.32, p[1], 0.01);
  213. assertPathEquals(['M', 58.66, 70, 'A', 10, 20, 30, 30, 55, 77.32], path);
  214. }
  215. function testArcNonConnectClose() {
  216. var path = new goog.math.Path();
  217. path.moveTo(0, 0);
  218. path.arc(10, 10, 10, 10, -90, 180, false);
  219. assertObjectEquals([10, 20], path.getCurrentPoint());
  220. path.close();
  221. assertObjectEquals([10, 0], path.getCurrentPoint());
  222. }
  223. function testRepeatedArc() {
  224. var path = new goog.math.Path();
  225. path.arc(50, 60, 10, 20, 30, 30, false);
  226. path.arc(50, 60, 10, 20, 60, 30, false);
  227. assertFalse(path.isSimple());
  228. assertObjectEquals([50, 80], path.getCurrentPoint());
  229. assertPathEquals(
  230. [
  231. 'M', 58.66, 70, 'A', 10, 20, 30, 30, 55, 77.32,
  232. 'M', 55, 77.32, 'A', 10, 20, 60, 30, 50, 80
  233. ],
  234. path);
  235. }
  236. function testRepeatedArc2() {
  237. var path = new goog.math.Path();
  238. path.arc(50, 60, 10, 20, 30, 30, false);
  239. path.arc(50, 60, 10, 20, 60, 30, true);
  240. assertPathEquals(
  241. [
  242. 'M', 58.66, 70, 'A', 10, 20, 30, 30, 55, 77.32, 'A', 10, 20, 60, 30, 50,
  243. 80
  244. ],
  245. path);
  246. }
  247. function testCompleteCircle() {
  248. var path = new goog.math.Path();
  249. path.arc(0, 0, 10, 10, 0, 360, false);
  250. assertFalse(path.isSimple());
  251. var p = path.getCurrentPoint();
  252. assertRoughlyEquals(10, p[0], 0.01);
  253. assertRoughlyEquals(0, p[1], 0.01);
  254. assertPathEquals(['M', 10, 0, 'A', 10, 10, 0, 360, 10, 0], path);
  255. }
  256. function testClose() {
  257. var path = new goog.math.Path();
  258. assertThrows('Path cannot start with close', function() { path.close(); });
  259. path.moveTo(0, 0);
  260. path.lineTo(10, 20, 30, 40, 50, 60);
  261. path.close();
  262. assertTrue(path.isSimple());
  263. assertObjectEquals([0, 0], path.getCurrentPoint());
  264. assertPathEquals(['M', 0, 0, 'L', 10, 20, 30, 40, 50, 60, 'X'], path);
  265. }
  266. function testClear() {
  267. var path = new goog.math.Path();
  268. path.moveTo(0, 0);
  269. path.arc(50, 60, 10, 20, 30, 30, false);
  270. path.clear();
  271. assertTrue(path.isSimple());
  272. assertNull(path.getCurrentPoint());
  273. assertPathEquals([], path);
  274. }
  275. function testCreateSimplifiedPath() {
  276. var path = new goog.math.Path();
  277. path.moveTo(0, 0);
  278. path.arc(50, 60, 10, 20, 30, 30, false);
  279. assertFalse(path.isSimple());
  280. path = goog.math.Path.createSimplifiedPath(path);
  281. assertTrue(path.isSimple());
  282. var p = path.getCurrentPoint();
  283. assertEquals(55, p[0]);
  284. assertRoughlyEquals(77.32, p[1], 0.01);
  285. assertPathEquals(
  286. ['M', 58.66, 70, 'C', 57.78, 73.04, 56.52, 75.57, 55, 77.32], path);
  287. }
  288. function testCreateSimplifiedPath2() {
  289. var path = new goog.math.Path();
  290. path.arc(50, 60, 10, 20, 30, 30, false);
  291. path.arc(50, 60, 10, 20, 60, 30, false);
  292. assertFalse(path.isSimple());
  293. path = goog.math.Path.createSimplifiedPath(path);
  294. assertTrue(path.isSimple());
  295. assertPathEquals(
  296. [
  297. 'M', 58.66, 70, 'C', 57.78, 73.04, 56.52, 75.57, 55, 77.32,
  298. 'M', 55, 77.32, 'C', 53.48, 79.08, 51.76, 80, 50, 80
  299. ],
  300. path);
  301. }
  302. function testCreateSimplifiedPath3() {
  303. var path = new goog.math.Path();
  304. path.arc(50, 60, 10, 20, 30, 30, false);
  305. path.arc(50, 60, 10, 20, 60, 30, true);
  306. path.close();
  307. path = goog.math.Path.createSimplifiedPath(path);
  308. assertPathEquals(
  309. [
  310. 'M', 58.66, 70, 'C', 57.78, 73.04, 56.52, 75.57, 55, 77.32, 53.48,
  311. 79.08, 51.76, 80, 50, 80, 'X'
  312. ],
  313. path);
  314. var p = path.getCurrentPoint();
  315. assertRoughlyEquals(58.66, p[0], 0.01);
  316. assertRoughlyEquals(70, p[1], 0.01);
  317. }
  318. function testArcToAsCurves() {
  319. var path = new goog.math.Path();
  320. path.moveTo(58.66, 70);
  321. path.arcToAsCurves(10, 20, 30, 30);
  322. assertPathEquals(
  323. ['M', 58.66, 70, 'C', 57.78, 73.04, 56.52, 75.57, 55, 77.32], path);
  324. }
  325. function testCreateTransformedPath() {
  326. var path = new goog.math.Path();
  327. path.moveTo(0, 0);
  328. path.lineTo(0, 10, 10, 10, 10, 0);
  329. path.close();
  330. var tx = new goog.math.AffineTransform(2, 0, 0, 3, 10, 20);
  331. var path2 = path.createTransformedPath(tx);
  332. assertPathEquals(['M', 0, 0, 'L', 0, 10, 10, 10, 10, 0, 'X'], path);
  333. assertPathEquals(['M', 10, 20, 'L', 10, 50, 30, 50, 30, 20, 'X'], path2);
  334. }
  335. function testTransform() {
  336. var path = new goog.math.Path();
  337. path.moveTo(0, 0);
  338. path.lineTo(0, 10, 10, 10, 10, 0);
  339. path.close();
  340. var tx = new goog.math.AffineTransform(2, 0, 0, 3, 10, 20);
  341. var path2 = path.transform(tx);
  342. assertTrue(path === path2);
  343. assertPathEquals(['M', 10, 20, 'L', 10, 50, 30, 50, 30, 20, 'X'], path2);
  344. }
  345. function testTransformCurrentAndClosePoints() {
  346. var path = new goog.math.Path();
  347. path.moveTo(0, 0);
  348. assertObjectEquals([0, 0], path.getCurrentPoint());
  349. path.transform(new goog.math.AffineTransform(1, 0, 0, 1, 10, 20));
  350. assertObjectEquals([10, 20], path.getCurrentPoint());
  351. path.lineTo(50, 50);
  352. path.close();
  353. assertObjectEquals([10, 20], path.getCurrentPoint());
  354. }
  355. function testTransformNonSimple() {
  356. var path = new goog.math.Path();
  357. path.arc(50, 60, 10, 20, 30, 30, false);
  358. assertThrows(function() {
  359. path.transform(new goog.math.AffineTransform(1, 0, 0, 1, 10, 20));
  360. });
  361. }
  362. function testAppendPath() {
  363. var path1 = new goog.math.Path();
  364. path1.moveTo(0, 0);
  365. path1.lineTo(0, 10, 10, 10, 10, 0);
  366. path1.close();
  367. var path2 = new goog.math.Path();
  368. path2.arc(50, 60, 10, 20, 30, 30, false);
  369. assertTrue(path1.isSimple());
  370. path1.appendPath(path2);
  371. assertFalse(path1.isSimple());
  372. assertPathEquals(
  373. [
  374. 'M', 0, 0, 'L', 0, 10, 10, 10, 10, 0, 'X',
  375. 'M', 58.66, 70, 'A', 10, 20, 30, 30, 55, 77.32
  376. ],
  377. path1);
  378. }
  379. function testIsEmpty() {
  380. var path = new goog.math.Path();
  381. assertTrue('Initially path is empty', path.isEmpty());
  382. path.moveTo(0, 0);
  383. assertFalse('After command addition, path is not empty', path.isEmpty());
  384. path.clear();
  385. assertTrue('After clear, path is empty again', path.isEmpty());
  386. }
  387. function testGetSegmentTypes() {
  388. var path = new goog.math.Path();
  389. path.moveTo(0, 0);
  390. path.lineTo(10, 20, 30, 40);
  391. path.close();
  392. var Segment = goog.math.Path.Segment;
  393. var segmentTypes = path.getSegmentTypes();
  394. assertArrayEquals(
  395. 'The returned segment types do not match the expected values',
  396. [Segment.MOVETO, Segment.LINETO, Segment.CLOSE], segmentTypes);
  397. segmentTypes[2] = Segment.LINETO;
  398. assertArrayEquals(
  399. 'Modifying the returned segment types changed the path',
  400. [Segment.MOVETO, Segment.LINETO, Segment.CLOSE], path.getSegmentTypes());
  401. }
  402. function testGetSegmentCounts() {
  403. var path = new goog.math.Path();
  404. path.moveTo(0, 0);
  405. path.lineTo(10, 20, 30, 40);
  406. path.close();
  407. var segmentTypes = path.getSegmentCounts();
  408. assertArrayEquals(
  409. 'The returned segment counts do not match the expected values', [1, 2, 1],
  410. segmentTypes);
  411. segmentTypes[1] = 3;
  412. assertArrayEquals(
  413. 'Modifying the returned segment counts changed the path', [1, 2, 1],
  414. path.getSegmentCounts());
  415. }
  416. function testGetSegmentArgs() {
  417. var path = new goog.math.Path();
  418. path.moveTo(0, 0);
  419. path.lineTo(10, 20, 30, 40);
  420. path.close();
  421. var segmentTypes = path.getSegmentArgs();
  422. assertArrayEquals(
  423. 'The returned segment args do not match the expected values',
  424. [0, 0, 10, 20, 30, 40], segmentTypes);
  425. segmentTypes[1] = -10;
  426. assertArrayEquals(
  427. 'Modifying the returned segment args changed the path',
  428. [0, 0, 10, 20, 30, 40], path.getSegmentArgs());
  429. }