lineclip.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. "use strict";
  2. // Cohen-Sutherland line clipping algorithm, adapted to efficiently
  3. // handle polylines rather than just segments
  4. Object.defineProperty(exports, "__esModule", { value: true });
  5. function lineclip(points, bbox, result) {
  6. var len = points.length, codeA = bitCode(points[0], bbox), part = [], i, codeB, lastCode;
  7. var a;
  8. var b;
  9. if (!result)
  10. result = [];
  11. for (i = 1; i < len; i++) {
  12. a = points[i - 1];
  13. b = points[i];
  14. codeB = lastCode = bitCode(b, bbox);
  15. while (true) {
  16. if (!(codeA | codeB)) {
  17. // accept
  18. part.push(a);
  19. if (codeB !== lastCode) {
  20. // segment went outside
  21. part.push(b);
  22. if (i < len - 1) {
  23. // start a new line
  24. result.push(part);
  25. part = [];
  26. }
  27. }
  28. else if (i === len - 1) {
  29. part.push(b);
  30. }
  31. break;
  32. }
  33. else if (codeA & codeB) {
  34. // trivial reject
  35. break;
  36. }
  37. else if (codeA) {
  38. // a outside, intersect with clip edge
  39. a = intersect(a, b, codeA, bbox);
  40. codeA = bitCode(a, bbox);
  41. }
  42. else {
  43. // b outside
  44. b = intersect(a, b, codeB, bbox);
  45. codeB = bitCode(b, bbox);
  46. }
  47. }
  48. codeA = lastCode;
  49. }
  50. if (part.length)
  51. result.push(part);
  52. return result;
  53. }
  54. exports.lineclip = lineclip;
  55. // Sutherland-Hodgeman polygon clipping algorithm
  56. function polygonclip(points, bbox) {
  57. var result, edge, prev, prevInside, i, p, inside;
  58. // clip against each side of the clip rectangle
  59. for (edge = 1; edge <= 8; edge *= 2) {
  60. result = [];
  61. prev = points[points.length - 1];
  62. prevInside = !(bitCode(prev, bbox) & edge);
  63. for (i = 0; i < points.length; i++) {
  64. p = points[i];
  65. inside = !(bitCode(p, bbox) & edge);
  66. // if segment goes through the clip window, add an intersection
  67. if (inside !== prevInside)
  68. result.push(intersect(prev, p, edge, bbox));
  69. if (inside)
  70. result.push(p); // add a point if it's inside
  71. prev = p;
  72. prevInside = inside;
  73. }
  74. points = result;
  75. if (!points.length)
  76. break;
  77. }
  78. return result;
  79. }
  80. exports.polygonclip = polygonclip;
  81. // intersect a segment against one of the 4 lines that make up the bbox
  82. function intersect(a, b, edge, bbox) {
  83. return edge & 8
  84. ? [a[0] + ((b[0] - a[0]) * (bbox[3] - a[1])) / (b[1] - a[1]), bbox[3]] // top
  85. : edge & 4
  86. ? [a[0] + ((b[0] - a[0]) * (bbox[1] - a[1])) / (b[1] - a[1]), bbox[1]] // bottom
  87. : edge & 2
  88. ? [bbox[2], a[1] + ((b[1] - a[1]) * (bbox[2] - a[0])) / (b[0] - a[0])] // right
  89. : edge & 1
  90. ? [bbox[0], a[1] + ((b[1] - a[1]) * (bbox[0] - a[0])) / (b[0] - a[0])] // left
  91. : null;
  92. }
  93. // bit code reflects the point position relative to the bbox:
  94. // left mid right
  95. // top 1001 1000 1010
  96. // mid 0001 0000 0010
  97. // bottom 0101 0100 0110
  98. function bitCode(p, bbox) {
  99. var code = 0;
  100. if (p[0] < bbox[0])
  101. code |= 1;
  102. // left
  103. else if (p[0] > bbox[2])
  104. code |= 2; // right
  105. if (p[1] < bbox[1])
  106. code |= 4;
  107. // bottom
  108. else if (p[1] > bbox[3])
  109. code |= 8; // top
  110. return code;
  111. }