bitmap-sdf.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. /* This file is automatically rebuilt by the Cesium build process. */
  2. var clamp_1 = clamp;
  3. function clamp(value, min, max) {
  4. return min < max
  5. ? (value < min ? min : value > max ? max : value)
  6. : (value < max ? max : value > min ? min : value)
  7. }
  8. var bitmapSdf = calcSDF;
  9. var INF = 1e20;
  10. function calcSDF(src, options) {
  11. if (!options) options = {};
  12. var cutoff = options.cutoff == null ? 0.25 : options.cutoff;
  13. var radius = options.radius == null ? 8 : options.radius;
  14. var channel = options.channel || 0;
  15. var w, h, size, data, intData, stride, ctx, canvas, imgData, i, l;
  16. // handle image container
  17. if (ArrayBuffer.isView(src) || Array.isArray(src)) {
  18. if (!options.width || !options.height) throw Error('For raw data width and height should be provided by options')
  19. w = options.width, h = options.height;
  20. data = src;
  21. if (!options.stride) stride = Math.floor(src.length / w / h);
  22. else stride = options.stride;
  23. }
  24. else {
  25. if (window.HTMLCanvasElement && src instanceof window.HTMLCanvasElement) {
  26. canvas = src;
  27. ctx = canvas.getContext('2d');
  28. w = canvas.width, h = canvas.height;
  29. imgData = ctx.getImageData(0, 0, w, h);
  30. data = imgData.data;
  31. stride = 4;
  32. }
  33. else if (window.CanvasRenderingContext2D && src instanceof window.CanvasRenderingContext2D) {
  34. canvas = src.canvas;
  35. ctx = src;
  36. w = canvas.width, h = canvas.height;
  37. imgData = ctx.getImageData(0, 0, w, h);
  38. data = imgData.data;
  39. stride = 4;
  40. }
  41. else if (window.ImageData && src instanceof window.ImageData) {
  42. imgData = src;
  43. w = src.width, h = src.height;
  44. data = imgData.data;
  45. stride = 4;
  46. }
  47. }
  48. size = Math.max(w, h);
  49. //convert int data to floats
  50. if ((window.Uint8ClampedArray && data instanceof window.Uint8ClampedArray) || (window.Uint8Array && data instanceof window.Uint8Array)) {
  51. intData = data;
  52. data = Array(w*h);
  53. for (i = 0, l = intData.length; i < l; i++) {
  54. data[i] = intData[i*stride + channel] / 255;
  55. }
  56. }
  57. else {
  58. if (stride !== 1) throw Error('Raw data can have only 1 value per pixel')
  59. }
  60. // temporary arrays for the distance transform
  61. var gridOuter = Array(w * h);
  62. var gridInner = Array(w * h);
  63. var f = Array(size);
  64. var d = Array(size);
  65. var z = Array(size + 1);
  66. var v = Array(size);
  67. for (i = 0, l = w * h; i < l; i++) {
  68. var a = data[i];
  69. gridOuter[i] = a === 1 ? 0 : a === 0 ? INF : Math.pow(Math.max(0, 0.5 - a), 2);
  70. gridInner[i] = a === 1 ? INF : a === 0 ? 0 : Math.pow(Math.max(0, a - 0.5), 2);
  71. }
  72. edt(gridOuter, w, h, f, d, v, z);
  73. edt(gridInner, w, h, f, d, v, z);
  74. var dist = window.Float32Array ? new Float32Array(w * h) : new Array(w * h);
  75. for (i = 0, l = w*h; i < l; i++) {
  76. dist[i] = clamp_1(1 - ( (gridOuter[i] - gridInner[i]) / radius + cutoff), 0, 1);
  77. }
  78. return dist
  79. }
  80. // 2D Euclidean distance transform by Felzenszwalb & Huttenlocher https://cs.brown.edu/~pff/dt/
  81. function edt(data, width, height, f, d, v, z) {
  82. for (var x = 0; x < width; x++) {
  83. for (var y = 0; y < height; y++) {
  84. f[y] = data[y * width + x];
  85. }
  86. edt1d(f, d, v, z, height);
  87. for (y = 0; y < height; y++) {
  88. data[y * width + x] = d[y];
  89. }
  90. }
  91. for (y = 0; y < height; y++) {
  92. for (x = 0; x < width; x++) {
  93. f[x] = data[y * width + x];
  94. }
  95. edt1d(f, d, v, z, width);
  96. for (x = 0; x < width; x++) {
  97. data[y * width + x] = Math.sqrt(d[x]);
  98. }
  99. }
  100. }
  101. // 1D squared distance transform
  102. function edt1d(f, d, v, z, n) {
  103. v[0] = 0;
  104. z[0] = -INF;
  105. z[1] = +INF;
  106. for (var q = 1, k = 0; q < n; q++) {
  107. var s = ((f[q] + q * q) - (f[v[k]] + v[k] * v[k])) / (2 * q - 2 * v[k]);
  108. while (s <= z[k]) {
  109. k--;
  110. s = ((f[q] + q * q) - (f[v[k]] + v[k] * v[k])) / (2 * q - 2 * v[k]);
  111. }
  112. k++;
  113. v[k] = q;
  114. z[k] = s;
  115. z[k + 1] = +INF;
  116. }
  117. for (q = 0, k = 0; q < n; q++) {
  118. while (z[k + 1] < q) k++;
  119. d[q] = (q - v[k]) * (q - v[k]) + f[v[k]];
  120. }
  121. }
  122. export { bitmapSdf as default };