arc.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. var util_1 = require("./util");
  4. var ellipse_1 = require("./ellipse");
  5. // 偏导数 x
  6. function derivativeXAt(cx, cy, rx, ry, xRotation, startAngle, endAngle, angle) {
  7. return -1 * rx * Math.cos(xRotation) * Math.sin(angle) - ry * Math.sin(xRotation) * Math.cos(angle);
  8. }
  9. // 偏导数 y
  10. function derivativeYAt(cx, cy, rx, ry, xRotation, startAngle, endAngle, angle) {
  11. return -1 * rx * Math.sin(xRotation) * Math.sin(angle) + ry * Math.cos(xRotation) * Math.cos(angle);
  12. }
  13. // x 的极值
  14. function xExtrema(rx, ry, xRotation) {
  15. return Math.atan((-ry / rx) * Math.tan(xRotation));
  16. }
  17. // y 的极值
  18. function yExtrema(rx, ry, xRotation) {
  19. return Math.atan(ry / (rx * Math.tan(xRotation)));
  20. }
  21. // 根据角度求 x 坐标
  22. function xAt(cx, cy, rx, ry, xRotation, angle) {
  23. return rx * Math.cos(xRotation) * Math.cos(angle) - ry * Math.sin(xRotation) * Math.sin(angle) + cx;
  24. }
  25. // 根据角度求 y 坐标
  26. function yAt(cx, cy, rx, ry, xRotation, angle) {
  27. return rx * Math.sin(xRotation) * Math.cos(angle) + ry * Math.cos(xRotation) * Math.sin(angle) + cy;
  28. }
  29. // 获取点在椭圆上的角度
  30. function getAngle(rx, ry, x0, y0) {
  31. var angle = Math.atan2(y0 * rx, x0 * ry);
  32. // 转换到 0 - 2PI 内
  33. return (angle + Math.PI * 2) % (Math.PI * 2);
  34. }
  35. // 根据角度获取,x,y
  36. function getPoint(rx, ry, angle) {
  37. return {
  38. x: rx * Math.cos(angle),
  39. y: ry * Math.sin(angle),
  40. };
  41. }
  42. // 旋转
  43. function rotate(x, y, angle) {
  44. var cos = Math.cos(angle);
  45. var sin = Math.sin(angle);
  46. return [x * cos - y * sin, x * sin + y * cos];
  47. }
  48. exports.default = {
  49. /**
  50. * 计算包围盒
  51. * @param {number} cx 圆心 x
  52. * @param {number} cy 圆心 y
  53. * @param {number} rx x 轴方向的半径
  54. * @param {number} ry y 轴方向的半径
  55. * @param {number} xRotation 旋转角度
  56. * @param {number} startAngle 起始角度
  57. * @param {number} endAngle 结束角度
  58. * @return {object} 包围盒对象
  59. */
  60. box: function (cx, cy, rx, ry, xRotation, startAngle, endAngle) {
  61. var xDim = xExtrema(rx, ry, xRotation);
  62. var minX = Infinity;
  63. var maxX = -Infinity;
  64. var xs = [startAngle, endAngle];
  65. for (var i = -Math.PI * 2; i <= Math.PI * 2; i += Math.PI) {
  66. var xAngle = xDim + i;
  67. if (startAngle < endAngle) {
  68. if (startAngle < xAngle && xAngle < endAngle) {
  69. xs.push(xAngle);
  70. }
  71. }
  72. else {
  73. if (endAngle < xAngle && xAngle < startAngle) {
  74. xs.push(xAngle);
  75. }
  76. }
  77. }
  78. for (var i = 0; i < xs.length; i++) {
  79. var x = xAt(cx, cy, rx, ry, xRotation, xs[i]);
  80. if (x < minX) {
  81. minX = x;
  82. }
  83. if (x > maxX) {
  84. maxX = x;
  85. }
  86. }
  87. var yDim = yExtrema(rx, ry, xRotation);
  88. var minY = Infinity;
  89. var maxY = -Infinity;
  90. var ys = [startAngle, endAngle];
  91. for (var i = -Math.PI * 2; i <= Math.PI * 2; i += Math.PI) {
  92. var yAngle = yDim + i;
  93. if (startAngle < endAngle) {
  94. if (startAngle < yAngle && yAngle < endAngle) {
  95. ys.push(yAngle);
  96. }
  97. }
  98. else {
  99. if (endAngle < yAngle && yAngle < startAngle) {
  100. ys.push(yAngle);
  101. }
  102. }
  103. }
  104. for (var i = 0; i < ys.length; i++) {
  105. var y = yAt(cx, cy, rx, ry, xRotation, ys[i]);
  106. if (y < minY) {
  107. minY = y;
  108. }
  109. if (y > maxY) {
  110. maxY = y;
  111. }
  112. }
  113. return {
  114. x: minX,
  115. y: minY,
  116. width: maxX - minX,
  117. height: maxY - minY,
  118. };
  119. },
  120. /**
  121. * 获取圆弧的长度,计算圆弧长度时不考虑旋转角度,
  122. * 仅跟 rx, ry, startAngle, endAngle 相关
  123. * @param {number} cx 圆心 x
  124. * @param {number} cy 圆心 y
  125. * @param {number} rx x 轴方向的半径
  126. * @param {number} ry y 轴方向的半径
  127. * @param {number} xRotation 旋转角度
  128. * @param {number} startAngle 起始角度
  129. * @param {number} endAngle 结束角度
  130. */
  131. length: function (cx, cy, rx, ry, xRotation, startAngle, endAngle) { },
  132. /**
  133. * 获取指定点到圆弧的最近距离的点
  134. * @param {number} cx 圆心 x
  135. * @param {number} cy 圆心 y
  136. * @param {number} rx x 轴方向的半径
  137. * @param {number} ry y 轴方向的半径
  138. * @param {number} xRotation 旋转角度
  139. * @param {number} startAngle 起始角度
  140. * @param {number} endAngle 结束角度
  141. * @param {number} x0 指定点的 x
  142. * @param {number} y0 指定点的 y
  143. * @return {object} 到指定点最近距离的点
  144. */
  145. nearestPoint: function (cx, cy, rx, ry, xRotation, startAngle, endAngle, x0, y0) {
  146. // 将最近距离问题转换成到椭圆中心 0,0 没有旋转的椭圆问题
  147. var relativeVector = rotate(x0 - cx, y0 - cy, -xRotation);
  148. var x1 = relativeVector[0], y1 = relativeVector[1];
  149. // 计算点到椭圆的最近的点
  150. var relativePoint = ellipse_1.default.nearestPoint(0, 0, rx, ry, x1, y1);
  151. // 获取点在椭圆上的角度
  152. var angle = getAngle(rx, ry, relativePoint.x, relativePoint.y);
  153. // 点没有在圆弧上
  154. if (angle < startAngle) {
  155. // 小于起始圆弧
  156. relativePoint = getPoint(rx, ry, startAngle);
  157. }
  158. else if (angle > endAngle) {
  159. // 大于结束圆弧
  160. relativePoint = getPoint(rx, ry, endAngle);
  161. }
  162. // 旋转到 xRotation 的角度
  163. var vector = rotate(relativePoint.x, relativePoint.y, xRotation);
  164. return {
  165. x: vector[0] + cx,
  166. y: vector[1] + cy,
  167. };
  168. },
  169. pointDistance: function (cx, cy, rx, ry, xRotation, startAngle, endAngle, x0, y0) {
  170. var nearestPoint = this.nearestPoint(cx, cy, rx, ry, x0, y0);
  171. return util_1.distance(nearestPoint.x, nearestPoint.y, x0, y0);
  172. },
  173. pointAt: function (cx, cy, rx, ry, xRotation, startAngle, endAngle, t) {
  174. var angle = (endAngle - startAngle) * t + startAngle;
  175. return {
  176. x: xAt(cx, cy, rx, ry, xRotation, angle),
  177. y: yAt(cx, cy, rx, ry, xRotation, angle),
  178. };
  179. },
  180. tangentAngle: function (cx, cy, rx, ry, xRotation, startAngle, endAngle, t) {
  181. var angle = (endAngle - startAngle) * t + startAngle;
  182. var dx = derivativeXAt(cx, cy, rx, ry, xRotation, startAngle, endAngle, angle);
  183. var dy = derivativeYAt(cx, cy, rx, ry, xRotation, startAngle, endAngle, angle);
  184. return util_1.piMod(Math.atan2(dy, dx));
  185. },
  186. };
  187. //# sourceMappingURL=arc.js.map