line.test.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. const __1 = require("..");
  4. describe('Line', () => {
  5. describe('#constructor', () => {
  6. it('should create a line instance', () => {
  7. expect(new __1.Line()).toBeInstanceOf(__1.Line);
  8. expect(new __1.Line([1, 1], [2, 2])).toBeInstanceOf(__1.Line);
  9. expect(new __1.Line(1, 1, 2, 2)).toBeInstanceOf(__1.Line);
  10. expect(new __1.Line({ x: 1, y: 1 }, { x: 2, y: 2 })).toBeInstanceOf(__1.Line);
  11. });
  12. });
  13. describe('#Line.isLine', () => {
  14. it('should return true when the given object a line instance', () => {
  15. expect(__1.Line.isLine(new __1.Line(1, 2, 3, 4))).toBeTruthy();
  16. });
  17. it('should return false when the given object is not a line instance', () => {
  18. expect(__1.Line.isLine({ x: 1, y: 1 })).toBeFalsy();
  19. });
  20. });
  21. describe('#getCenter', () => {
  22. it('should return the center of the line', () => {
  23. const line = new __1.Line(2, 2, 4, 4);
  24. expect(line.getCenter().toJSON()).toEqual({ x: 3, y: 3 });
  25. });
  26. });
  27. describe('#round', () => {
  28. it('should round x and y properties to the given precision', () => {
  29. const line = new __1.Line(17.231, 4.01, 5.123, 3.75);
  30. line.round(2);
  31. expect(line.toJSON()).toEqual({
  32. start: { x: 17.23, y: 4.01 },
  33. end: { x: 5.12, y: 3.75 },
  34. });
  35. line.round();
  36. expect(line.toJSON()).toEqual({
  37. start: { x: 17, y: 4 },
  38. end: { x: 5, y: 4 },
  39. });
  40. });
  41. });
  42. describe('#translate', () => {
  43. it('should translate line by adding the given dx and dy values respectively', () => {
  44. const line = new __1.Line(1, 2, 3, 4);
  45. line.translate(2, 3);
  46. expect(line.toJSON()).toEqual({
  47. start: { x: 3, y: 5 },
  48. end: { x: 5, y: 7 },
  49. });
  50. line.translate(new __1.Point(-2, 4));
  51. expect(line.toJSON()).toEqual({
  52. start: { x: 1, y: 9 },
  53. end: { x: 3, y: 11 },
  54. });
  55. });
  56. });
  57. describe('#scale', () => {
  58. it('should scale line with the given amount', () => {
  59. expect(new __1.Line(1, 2, 3, 4).scale(2, 3).serialize()).toEqual('2 6 6 12');
  60. });
  61. it('should scale line with the given amount and center ', () => {
  62. expect(new __1.Line(1, 2, 3, 4).scale(2, 3, new __1.Point(40, 45)).serialize()).toEqual('-38 -84 -34 -78');
  63. });
  64. });
  65. describe('#rotate', () => {
  66. const rotate = (line, angle, center) => line.clone().rotate(angle, center).round(3).serialize();
  67. it('should rotate the line', () => {
  68. const line = new __1.Line(1, 2, 3, 4);
  69. let angle;
  70. const zeroPoint = new __1.Point(0, 0);
  71. const arbitraryPoint = new __1.Point(14, 6);
  72. angle = 0;
  73. expect(rotate(line, angle)).toEqual('1 2 3 4');
  74. expect(rotate(line, angle, zeroPoint)).toEqual('1 2 3 4');
  75. expect(rotate(line, angle, arbitraryPoint)).toEqual('1 2 3 4');
  76. angle = 154;
  77. expect(rotate(line, angle)).toEqual('-0.022 -2.236 -0.943 -4.91');
  78. expect(rotate(line, angle, zeroPoint)).toEqual('-0.022 -2.236 -0.943 -4.91');
  79. expect(rotate(line, angle, arbitraryPoint)).toEqual('23.931 15.294 23.01 12.62');
  80. });
  81. });
  82. describe('#length', () => {
  83. it('should return the length of the line', () => {
  84. expect(new __1.Line(0, 0, 0, 0).length()).toEqual(0);
  85. expect(new __1.Line(0, 0, 3, 4).length()).toEqual(5);
  86. });
  87. });
  88. describe('#squaredLength', () => {
  89. it('should return the squared length of the line', () => {
  90. expect(new __1.Line(0, 0, 0, 0).squaredLength()).toEqual(0);
  91. expect(new __1.Line(0, 0, 3, 4).squaredLength()).toEqual(25);
  92. });
  93. });
  94. describe('#setLength', () => {
  95. it('should set the length of the line by scale the line', () => {
  96. expect(new __1.Line(0, 0, 0, 0).setLength(100).serialize()).toEqual('0 0 0 0');
  97. expect(new __1.Line(0, 0, 3, 4).setLength(10).serialize()).toEqual('0 0 6 8');
  98. });
  99. });
  100. describe('#parallel', () => {
  101. it('should return the parallel line', () => {
  102. expect(new __1.Line(0, 0, 2, 0).parallel(10).round().serialize()).toEqual('0 10 2 10');
  103. expect(new __1.Line(0, 0, 0, 2).parallel(10).round().serialize()).toEqual('-10 0 -10 2');
  104. });
  105. it('should return the the cloned line when the line is undifferentiable', () => {
  106. expect(new __1.Line(3, 3, 3, 3).parallel(10).serialize()).toEqual('3 3 3 3');
  107. });
  108. });
  109. describe('#vector', () => {
  110. it('should return the vector of the line with length equal to length of the line', () => {
  111. expect(new __1.Line(1, 2, 3, 4).vector().toJSON()).toEqual({ x: 2, y: 2 });
  112. });
  113. });
  114. describe('#angle', () => {
  115. it('should return the angle of incline of the line', () => {
  116. expect(new __1.Line(0, 0, 0, 1).angle()).toEqual(90);
  117. });
  118. it('should return `NaN` if the start and end endpoints of the line both lie at the same coordinates', () => {
  119. expect(new __1.Line(0, 0, 0, 0).angle()).toBeNaN();
  120. expect(new __1.Line(1, 2, 1, 2).angle()).toBeNaN();
  121. });
  122. });
  123. describe('#bbox', () => {
  124. it('should return a rectangle that is the bounding box of the line', () => {
  125. const bbox = new __1.Line(1, 2, 3, 4).bbox();
  126. expect(bbox).toBeInstanceOf(__1.Rectangle);
  127. expect(bbox.toJSON()).toEqual({ x: 1, y: 2, width: 2, height: 2 });
  128. });
  129. });
  130. describe('#bearing', () => {
  131. it('should return the bearing (cardinal direction) of the line', () => {
  132. expect(new __1.Line(0, 0, 1, 0).bearing()).toEqual('E');
  133. expect(new __1.Line(0, 0, 0, 1).bearing()).toEqual('N');
  134. expect(new __1.Line(0, 0, 0, -1).bearing()).toEqual('S');
  135. expect(new __1.Line(0, 0, -1, 0).bearing()).toEqual('W');
  136. expect(new __1.Line(0, 0, 2, 1).bearing()).toEqual('NE');
  137. expect(new __1.Line(0, 0, 2, -1).bearing()).toEqual('SE');
  138. expect(new __1.Line(0, 0, -2, 1).bearing()).toEqual('NW');
  139. expect(new __1.Line(0, 0, -2, -1).bearing()).toEqual('SW');
  140. });
  141. });
  142. describe('#closestPoint', () => {
  143. it('should return the point on the line that lies closest to point `p`', () => {
  144. const line = new __1.Line(10, 0, 20, 0);
  145. expect(line.closestPoint([15, 0]).toJSON()).toEqual({ x: 15, y: 0 });
  146. expect(line.closestPoint([15, 20]).toJSON()).toEqual({ x: 15, y: 0 });
  147. expect(line.closestPoint([15, -20]).toJSON()).toEqual({ x: 15, y: 0 });
  148. expect(line.closestPoint([20, 10]).toJSON()).toEqual({ x: 20, y: 0 });
  149. expect(line.closestPoint([0, 10]).toJSON()).toEqual({ x: 10, y: 0 });
  150. expect(line.closestPoint([30, 10]).toJSON()).toEqual({ x: 20, y: 0 });
  151. expect(line.closestPoint([-10, 10]).toJSON()).toEqual({ x: 10, y: 0 });
  152. });
  153. });
  154. describe('#closestPointLength', () => {
  155. it('should return the length of the line up to the point that lies closest to point `p`', () => {
  156. const line = new __1.Line(10, 0, 20, 0);
  157. expect(line.closestPointLength([15, 0])).toEqual(5);
  158. expect(line.closestPointLength([15, 20])).toEqual(5);
  159. expect(line.closestPointLength([15, -20])).toEqual(5);
  160. expect(line.closestPointLength([20, 10])).toEqual(10);
  161. expect(line.closestPointLength([0, 10])).toEqual(0);
  162. expect(line.closestPointLength([30, 10])).toEqual(10);
  163. expect(line.closestPointLength([-10, 10])).toEqual(0);
  164. });
  165. });
  166. describe('#closestPointTangent', () => {
  167. it('should return a line that is tangent to the line at the point that lies closest to point `p`', () => {
  168. const line = new __1.Line(10, 0, 20, 0);
  169. const tangent = (x, y) => { var _a; return (_a = line.closestPointTangent({ x, y })) === null || _a === void 0 ? void 0 : _a.serialize(); };
  170. expect(tangent(15, 0)).toEqual('15 0 25 0');
  171. expect(tangent(15, 20)).toEqual('15 0 25 0');
  172. expect(tangent(15, -20)).toEqual('15 0 25 0');
  173. expect(tangent(20, 10)).toEqual('20 0 30 0');
  174. expect(tangent(0, 10)).toEqual('10 0 20 0');
  175. expect(tangent(30, 10)).toEqual('20 0 30 0');
  176. expect(tangent(-10, 10)).toEqual('10 0 20 0');
  177. });
  178. });
  179. describe('#closestPointNormalizedLength', () => {
  180. it('should return the normalized length (distance from the start of the line / total line length) of the line up to the point that lies closest to point', () => {
  181. const line = new __1.Line(10, 0, 20, 0);
  182. const length = (x, y) => line.closestPointNormalizedLength({ x, y });
  183. expect(length(15, 0)).toEqual(0.5);
  184. expect(length(15, 20)).toEqual(0.5);
  185. expect(length(15, -20)).toEqual(0.5);
  186. expect(length(20, 10)).toEqual(1);
  187. expect(length(0, 10)).toEqual(0);
  188. expect(length(30, 10)).toEqual(1);
  189. expect(length(-10, 10)).toEqual(0);
  190. });
  191. it('should return o when the line has zero length', () => {
  192. expect(new __1.Line(1, 2, 1, 2).closestPointNormalizedLength([1, 1])).toEqual(0);
  193. });
  194. });
  195. describe('#pointAt', () => {
  196. it('should return a point at given length ratio', () => {
  197. const line = new __1.Line(0, 0, 100, 0);
  198. expect(line.pointAt(0.4).toJSON()).toEqual({ x: 40, y: 0 });
  199. expect(line.pointAt(-1).toJSON()).toEqual({ x: 0, y: 0 });
  200. expect(line.pointAt(10).toJSON()).toEqual({ x: 100, y: 0 });
  201. });
  202. });
  203. describe('#pointAtLength', () => {
  204. it('should return a point on the line that lies length away from the beginning of the line', () => {
  205. const line = new __1.Line(0, 0, 100, 0);
  206. expect(line.pointAtLength(40).toJSON()).toEqual({ x: 40, y: 0 });
  207. expect(line.pointAtLength(1000).toJSON()).toEqual({ x: 100, y: 0 });
  208. expect(line.pointAtLength(-40).toJSON()).toEqual({ x: 60, y: 0 });
  209. expect(line.pointAtLength(-1000).toJSON()).toEqual({ x: 0, y: 0 });
  210. });
  211. });
  212. describe('#divideAt', () => {
  213. it('should return an array with two lines, divided at provided `ratio`', () => {
  214. const line = new __1.Line(10, 0, 20, 0);
  215. let lines = line.divideAt(0.5);
  216. expect(lines[0]).toBeInstanceOf(__1.Line);
  217. expect(lines[1]).toBeInstanceOf(__1.Line);
  218. expect(lines[0].serialize()).toEqual('10 0 15 0');
  219. expect(lines[1].serialize()).toEqual('15 0 20 0');
  220. lines = line.divideAt(0);
  221. expect(lines[0].serialize()).toEqual('10 0 10 0');
  222. expect(lines[1].serialize()).toEqual('10 0 20 0');
  223. lines = line.divideAt(-1);
  224. expect(lines[0].serialize()).toEqual('10 0 10 0');
  225. expect(lines[1].serialize()).toEqual('10 0 20 0');
  226. lines = line.divideAt(1);
  227. expect(lines[0].serialize()).toEqual('10 0 20 0');
  228. expect(lines[1].serialize()).toEqual('20 0 20 0');
  229. lines = line.divideAt(10);
  230. expect(lines[0].serialize()).toEqual('10 0 20 0');
  231. expect(lines[1].serialize()).toEqual('20 0 20 0');
  232. });
  233. });
  234. describe('#divideAtLength', () => {
  235. it('should return an array with two lines, divided at provided `length`', () => {
  236. const line = new __1.Line(10, 0, 20, 0);
  237. let lines = line.divideAtLength(5);
  238. expect(lines[0]).toBeInstanceOf(__1.Line);
  239. expect(lines[1]).toBeInstanceOf(__1.Line);
  240. expect(lines[0].serialize()).toEqual('10 0 15 0');
  241. expect(lines[1].serialize()).toEqual('15 0 20 0');
  242. lines = line.divideAtLength(-5);
  243. expect(lines[0].serialize()).toEqual('10 0 15 0');
  244. expect(lines[1].serialize()).toEqual('15 0 20 0');
  245. lines = line.divideAtLength(0);
  246. expect(lines[0].serialize()).toEqual('10 0 10 0');
  247. expect(lines[1].serialize()).toEqual('10 0 20 0');
  248. lines = line.divideAtLength(100);
  249. expect(lines[0].serialize()).toEqual('10 0 20 0');
  250. expect(lines[1].serialize()).toEqual('20 0 20 0');
  251. lines = line.divideAtLength(-100);
  252. expect(lines[0].serialize()).toEqual('10 0 10 0');
  253. expect(lines[1].serialize()).toEqual('10 0 20 0');
  254. });
  255. });
  256. describe('#containsPoint', () => {
  257. it('should return true if point lies on the line', () => {
  258. const line = new __1.Line(10, 0, 20, 0);
  259. expect(line.containsPoint({ x: 10, y: 0 })).toEqual(true);
  260. expect(line.containsPoint({ x: 15, y: 0 })).toEqual(true);
  261. expect(line.containsPoint({ x: 20, y: 0 })).toEqual(true);
  262. });
  263. it('should return false if point do not lie on the line', () => {
  264. const line = new __1.Line(10, 0, 20, 0);
  265. expect(line.containsPoint({ x: 5, y: 0 })).toEqual(false);
  266. expect(line.containsPoint({ x: 15, y: 10 })).toEqual(false);
  267. expect(line.containsPoint({ x: 25, y: 0 })).toEqual(false);
  268. });
  269. });
  270. describe('#intersect', () => {
  271. it('should return an intersection point for the line', () => {
  272. const line1 = new __1.Line(2, 4, 5, 1);
  273. const line2 = new __1.Line(2, 1, 5, 4);
  274. const line3 = new __1.Line(0, 2, 2, 8);
  275. expect(line1.intersect(line2)[0].serialize()).toEqual('3.5 2.5');
  276. expect(line1.intersect(line3)).toBeNull();
  277. });
  278. it('should return null for a rectangle that does not intersect the line', () => {
  279. const line = new __1.Line(0, 0, 0, -10);
  280. const rect = new __1.Rectangle(10, 20, 30, 40);
  281. expect(line.intersect(rect)).toBeNull();
  282. });
  283. it('should return one intersection point with the rectangle', () => {
  284. const rect = new __1.Rectangle(-10, -20, 30, 40);
  285. const line = new __1.Line(0, 0, 20, 0);
  286. const points = line.intersect(rect);
  287. expect(points.length).toEqual(1);
  288. expect(points[0].serialize()).toEqual('20 0');
  289. });
  290. it('should return one intersection points with the rectangle', () => {
  291. const rect = new __1.Rectangle(-10, -20, 30, 40);
  292. const line = new __1.Line(-20, 0, 20, 0);
  293. const points = line.intersect(rect);
  294. expect(points.length).toEqual(2);
  295. expect(points[0].serialize()).toEqual('20 0');
  296. expect(points[1].serialize()).toEqual('-10 0');
  297. });
  298. });
  299. describe('#intersectsWithLine', () => {
  300. it('should return an intersection point for the line', () => {
  301. const line1 = new __1.Line(0, 0, 8, 0);
  302. const line2 = new __1.Line(4, 4, 4, -4);
  303. const line3 = new __1.Line(0, 2, 2, 8);
  304. expect(line1.intersectsWithLine(line2).serialize()).toEqual('4 0');
  305. expect(line1.intersectsWithLine(line3)).toBeNull();
  306. });
  307. });
  308. describe('#isDifferentiable', () => {
  309. it('should return true if the line is differentiable', () => {
  310. expect(new __1.Line(1, 2, 3, 4).isDifferentiable()).toEqual(true);
  311. });
  312. it('should return false if the line is undifferentiable', () => {
  313. expect(new __1.Line(0, 0, 0, 0).isDifferentiable()).toEqual(false);
  314. expect(new __1.Line(1, 2, 1, 2).isDifferentiable()).toEqual(false);
  315. });
  316. });
  317. describe('#pointOffset', () => {
  318. it('should return the perpendicular distance', () => {
  319. const offset = (x1, y1, x2, y2, x, y) => new __1.Line(x1, y1, x2, y2).pointOffset({ x, y });
  320. expect(offset(0, 0, 1, 0, 50, 0)).toEqual(0);
  321. expect(offset(0, 0, 10, 0, 50, 10)).toEqual(10);
  322. expect(offset(0, 0, 100, 0, 50, -10)).toEqual(-10);
  323. });
  324. });
  325. describe('#pointSquaredDistance', () => {
  326. it('should renturn the squared distance between the line and the point', () => {
  327. const line = new __1.Line(0, 0, 10, 0);
  328. expect(line.pointSquaredDistance(2, 2)).toEqual(4);
  329. expect(line.pointSquaredDistance(2, 0)).toEqual(0);
  330. expect(line.pointSquaredDistance(2, -2)).toEqual(4);
  331. });
  332. });
  333. describe('#pointDistance', () => {
  334. it('should renturn the distance between the line and the point', () => {
  335. const line = new __1.Line(0, 0, 10, 0);
  336. expect(line.pointDistance(2, 2)).toEqual(2);
  337. expect(line.pointDistance(2, 0)).toEqual(0);
  338. expect(line.pointDistance(2, -2)).toEqual(2);
  339. });
  340. });
  341. describe('#tangentAt', () => {
  342. it('should return null when line is undifferentiable', () => {
  343. expect(new __1.Line(10, 10, 10, 10).tangentAt(0.5)).toBeNull();
  344. });
  345. it('should return a line tangent to line at given length ratio', () => {
  346. var _a, _b, _c;
  347. const line = new __1.Line(10, 10, 20, 20);
  348. expect((_a = line.tangentAt(0.4)) === null || _a === void 0 ? void 0 : _a.serialize()).toEqual('14 14 24 24');
  349. expect((_b = line.tangentAt(-1)) === null || _b === void 0 ? void 0 : _b.serialize()).toEqual('10 10 20 20');
  350. expect((_c = line.tangentAt(10)) === null || _c === void 0 ? void 0 : _c.serialize()).toEqual('20 20 30 30');
  351. });
  352. });
  353. describe('#tangentAtLength', () => {
  354. it('should return null when line is undifferentiable', () => {
  355. expect(new __1.Line(10, 10, 10, 10).tangentAtLength(5)).toBeNull();
  356. });
  357. it('should return a line tangent to line at given length', () => {
  358. var _a, _b, _c, _d;
  359. const line = new __1.Line(10, 10, 20, 20);
  360. expect((_a = line.tangentAtLength(4)) === null || _a === void 0 ? void 0 : _a.round(2).serialize()).toEqual('12.83 12.83 22.83 22.83');
  361. expect((_b = line.tangentAtLength(1000)) === null || _b === void 0 ? void 0 : _b.round(2).serialize()).toEqual('20 20 30 30');
  362. expect((_c = line.tangentAtLength(-4)) === null || _c === void 0 ? void 0 : _c.round(2).serialize()).toEqual('17.17 17.17 27.17 27.17');
  363. expect((_d = line.tangentAtLength(-1000)) === null || _d === void 0 ? void 0 : _d.round(2).serialize()).toEqual('10 10 20 20');
  364. });
  365. });
  366. describe('#relativeCcw', () => {
  367. it('should return 1 if the given point on the right side of the segment', () => {
  368. expect(new __1.Line(10, 10, 20, 20).relativeCcw(20, 15)).toEqual(1);
  369. });
  370. it('should return 0 if its on the segment', () => {
  371. expect(new __1.Line(10, 10, 20, 20).relativeCcw(15, 15)).toEqual(0);
  372. });
  373. it('should return -1 if the point is on the left side of the segment', () => {
  374. expect(new __1.Line(10, 10, 20, 20).relativeCcw(15, 20)).toEqual(-1);
  375. });
  376. });
  377. describe('#equals', () => {
  378. it('should return true when the given lines has the same start and end points', () => {
  379. expect(new __1.Line(1, 2, 3, 4).equals(new __1.Line([1, 2], [3, 4]))).toEqual(true);
  380. });
  381. it('should return false when the given lines has different start or end point', () => {
  382. expect(new __1.Line(1, 2, 3, 4).equals(new __1.Line([1, 2], [3, 40]))).toEqual(false);
  383. });
  384. });
  385. });
  386. //# sourceMappingURL=line.test.js.map