BoundingRect.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. import * as matrix from './matrix.js';
  2. import Point from './Point.js';
  3. var mathMin = Math.min;
  4. var mathMax = Math.max;
  5. var lt = new Point();
  6. var rb = new Point();
  7. var lb = new Point();
  8. var rt = new Point();
  9. var minTv = new Point();
  10. var maxTv = new Point();
  11. var BoundingRect = (function () {
  12. function BoundingRect(x, y, width, height) {
  13. if (width < 0) {
  14. x = x + width;
  15. width = -width;
  16. }
  17. if (height < 0) {
  18. y = y + height;
  19. height = -height;
  20. }
  21. this.x = x;
  22. this.y = y;
  23. this.width = width;
  24. this.height = height;
  25. }
  26. BoundingRect.prototype.union = function (other) {
  27. var x = mathMin(other.x, this.x);
  28. var y = mathMin(other.y, this.y);
  29. if (isFinite(this.x) && isFinite(this.width)) {
  30. this.width = mathMax(other.x + other.width, this.x + this.width) - x;
  31. }
  32. else {
  33. this.width = other.width;
  34. }
  35. if (isFinite(this.y) && isFinite(this.height)) {
  36. this.height = mathMax(other.y + other.height, this.y + this.height) - y;
  37. }
  38. else {
  39. this.height = other.height;
  40. }
  41. this.x = x;
  42. this.y = y;
  43. };
  44. BoundingRect.prototype.applyTransform = function (m) {
  45. BoundingRect.applyTransform(this, this, m);
  46. };
  47. BoundingRect.prototype.calculateTransform = function (b) {
  48. var a = this;
  49. var sx = b.width / a.width;
  50. var sy = b.height / a.height;
  51. var m = matrix.create();
  52. matrix.translate(m, m, [-a.x, -a.y]);
  53. matrix.scale(m, m, [sx, sy]);
  54. matrix.translate(m, m, [b.x, b.y]);
  55. return m;
  56. };
  57. BoundingRect.prototype.intersect = function (b, mtv) {
  58. if (!b) {
  59. return false;
  60. }
  61. if (!(b instanceof BoundingRect)) {
  62. b = BoundingRect.create(b);
  63. }
  64. var a = this;
  65. var ax0 = a.x;
  66. var ax1 = a.x + a.width;
  67. var ay0 = a.y;
  68. var ay1 = a.y + a.height;
  69. var bx0 = b.x;
  70. var bx1 = b.x + b.width;
  71. var by0 = b.y;
  72. var by1 = b.y + b.height;
  73. var overlap = !(ax1 < bx0 || bx1 < ax0 || ay1 < by0 || by1 < ay0);
  74. if (mtv) {
  75. var dMin = Infinity;
  76. var dMax = 0;
  77. var d0 = Math.abs(ax1 - bx0);
  78. var d1 = Math.abs(bx1 - ax0);
  79. var d2 = Math.abs(ay1 - by0);
  80. var d3 = Math.abs(by1 - ay0);
  81. var dx = Math.min(d0, d1);
  82. var dy = Math.min(d2, d3);
  83. if (ax1 < bx0 || bx1 < ax0) {
  84. if (dx > dMax) {
  85. dMax = dx;
  86. if (d0 < d1) {
  87. Point.set(maxTv, -d0, 0);
  88. }
  89. else {
  90. Point.set(maxTv, d1, 0);
  91. }
  92. }
  93. }
  94. else {
  95. if (dx < dMin) {
  96. dMin = dx;
  97. if (d0 < d1) {
  98. Point.set(minTv, d0, 0);
  99. }
  100. else {
  101. Point.set(minTv, -d1, 0);
  102. }
  103. }
  104. }
  105. if (ay1 < by0 || by1 < ay0) {
  106. if (dy > dMax) {
  107. dMax = dy;
  108. if (d2 < d3) {
  109. Point.set(maxTv, 0, -d2);
  110. }
  111. else {
  112. Point.set(maxTv, 0, d3);
  113. }
  114. }
  115. }
  116. else {
  117. if (dx < dMin) {
  118. dMin = dx;
  119. if (d2 < d3) {
  120. Point.set(minTv, 0, d2);
  121. }
  122. else {
  123. Point.set(minTv, 0, -d3);
  124. }
  125. }
  126. }
  127. }
  128. if (mtv) {
  129. Point.copy(mtv, overlap ? minTv : maxTv);
  130. }
  131. return overlap;
  132. };
  133. BoundingRect.prototype.contain = function (x, y) {
  134. var rect = this;
  135. return x >= rect.x
  136. && x <= (rect.x + rect.width)
  137. && y >= rect.y
  138. && y <= (rect.y + rect.height);
  139. };
  140. BoundingRect.prototype.clone = function () {
  141. return new BoundingRect(this.x, this.y, this.width, this.height);
  142. };
  143. BoundingRect.prototype.copy = function (other) {
  144. BoundingRect.copy(this, other);
  145. };
  146. BoundingRect.prototype.plain = function () {
  147. return {
  148. x: this.x,
  149. y: this.y,
  150. width: this.width,
  151. height: this.height
  152. };
  153. };
  154. BoundingRect.prototype.isFinite = function () {
  155. return isFinite(this.x)
  156. && isFinite(this.y)
  157. && isFinite(this.width)
  158. && isFinite(this.height);
  159. };
  160. BoundingRect.prototype.isZero = function () {
  161. return this.width === 0 || this.height === 0;
  162. };
  163. BoundingRect.create = function (rect) {
  164. return new BoundingRect(rect.x, rect.y, rect.width, rect.height);
  165. };
  166. BoundingRect.copy = function (target, source) {
  167. target.x = source.x;
  168. target.y = source.y;
  169. target.width = source.width;
  170. target.height = source.height;
  171. };
  172. BoundingRect.applyTransform = function (target, source, m) {
  173. if (!m) {
  174. if (target !== source) {
  175. BoundingRect.copy(target, source);
  176. }
  177. return;
  178. }
  179. if (m[1] < 1e-5 && m[1] > -1e-5 && m[2] < 1e-5 && m[2] > -1e-5) {
  180. var sx = m[0];
  181. var sy = m[3];
  182. var tx = m[4];
  183. var ty = m[5];
  184. target.x = source.x * sx + tx;
  185. target.y = source.y * sy + ty;
  186. target.width = source.width * sx;
  187. target.height = source.height * sy;
  188. if (target.width < 0) {
  189. target.x += target.width;
  190. target.width = -target.width;
  191. }
  192. if (target.height < 0) {
  193. target.y += target.height;
  194. target.height = -target.height;
  195. }
  196. return;
  197. }
  198. lt.x = lb.x = source.x;
  199. lt.y = rt.y = source.y;
  200. rb.x = rt.x = source.x + source.width;
  201. rb.y = lb.y = source.y + source.height;
  202. lt.transform(m);
  203. rt.transform(m);
  204. rb.transform(m);
  205. lb.transform(m);
  206. target.x = mathMin(lt.x, rb.x, lb.x, rt.x);
  207. target.y = mathMin(lt.y, rb.y, lb.y, rt.y);
  208. var maxX = mathMax(lt.x, rb.x, lb.x, rt.x);
  209. var maxY = mathMax(lt.y, rb.y, lb.y, rt.y);
  210. target.width = maxX - target.x;
  211. target.height = maxY - target.y;
  212. };
  213. return BoundingRect;
  214. }());
  215. export default BoundingRect;