sdf-error-estimation.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. #include "sdf-error-estimation.h"
  2. #include <cmath>
  3. #include "arithmetics.hpp"
  4. namespace msdfgen {
  5. void scanlineSDF(Scanline &line, const BitmapConstRef<float, 1> &sdf, const Projection &projection, double y, bool inverseYAxis) {
  6. if (!(sdf.width > 0 && sdf.height > 0))
  7. return line.setIntersections(std::vector<Scanline::Intersection>());
  8. double pixelY = clamp(projection.projectY(y)-.5, double(sdf.height-1));
  9. if (inverseYAxis)
  10. pixelY = sdf.height-1-pixelY;
  11. int b = (int) floor(pixelY);
  12. int t = b+1;
  13. double bt = pixelY-b;
  14. if (t >= sdf.height) {
  15. b = sdf.height-1;
  16. t = sdf.height-1;
  17. bt = 1;
  18. }
  19. bool inside = false;
  20. std::vector<Scanline::Intersection> intersections;
  21. float lv, rv = mix(*sdf(0, b), *sdf(0, t), bt);
  22. if ((inside = rv > .5f)) {
  23. Scanline::Intersection intersection = { -1e240, 1 };
  24. intersections.push_back(intersection);
  25. }
  26. for (int l = 0, r = 1; r < sdf.width; ++l, ++r) {
  27. lv = rv;
  28. rv = mix(*sdf(r, b), *sdf(r, t), bt);
  29. if (lv != rv) {
  30. double lr = double(.5f-lv)/double(rv-lv);
  31. if (lr >= 0 && lr <= 1) {
  32. Scanline::Intersection intersection = { projection.unprojectX(l+lr+.5), sign(rv-lv) };
  33. intersections.push_back(intersection);
  34. }
  35. }
  36. }
  37. #ifdef MSDFGEN_USE_CPP11
  38. line.setIntersections((std::vector<Scanline::Intersection> &&) intersections);
  39. #else
  40. line.setIntersections(intersections);
  41. #endif
  42. }
  43. template <int N>
  44. void scanlineMSDF(Scanline &line, const BitmapConstRef<float, N> &sdf, const Projection &projection, double y, bool inverseYAxis) {
  45. if (!(sdf.width > 0 && sdf.height > 0))
  46. return line.setIntersections(std::vector<Scanline::Intersection>());
  47. double pixelY = clamp(projection.projectY(y)-.5, double(sdf.height-1));
  48. if (inverseYAxis)
  49. pixelY = sdf.height-1-pixelY;
  50. int b = (int) floor(pixelY);
  51. int t = b+1;
  52. double bt = pixelY-b;
  53. if (t >= sdf.height) {
  54. b = sdf.height-1;
  55. t = sdf.height-1;
  56. bt = 1;
  57. }
  58. bool inside = false;
  59. std::vector<Scanline::Intersection> intersections;
  60. float lv[3], rv[3];
  61. rv[0] = mix(sdf(0, b)[0], sdf(0, t)[0], bt);
  62. rv[1] = mix(sdf(0, b)[1], sdf(0, t)[1], bt);
  63. rv[2] = mix(sdf(0, b)[2], sdf(0, t)[2], bt);
  64. if ((inside = median(rv[0], rv[1], rv[2]) > .5f)) {
  65. Scanline::Intersection intersection = { -1e240, 1 };
  66. intersections.push_back(intersection);
  67. }
  68. for (int l = 0, r = 1; r < sdf.width; ++l, ++r) {
  69. lv[0] = rv[0], lv[1] = rv[1], lv[2] = rv[2];
  70. rv[0] = mix(sdf(r, b)[0], sdf(r, t)[0], bt);
  71. rv[1] = mix(sdf(r, b)[1], sdf(r, t)[1], bt);
  72. rv[2] = mix(sdf(r, b)[2], sdf(r, t)[2], bt);
  73. Scanline::Intersection newIntersections[4];
  74. int newIntersectionCount = 0;
  75. for (int i = 0; i < 3; ++i) {
  76. if (lv[i] != rv[i]) {
  77. double lr = double(.5f-lv[i])/double(rv[i]-lv[i]);
  78. if (lr >= 0 && lr <= 1) {
  79. float v[3] = {
  80. mix(lv[0], rv[0], lr),
  81. mix(lv[1], rv[1], lr),
  82. mix(lv[2], rv[2], lr)
  83. };
  84. if (median(v[0], v[1], v[2]) == v[i]) {
  85. newIntersections[newIntersectionCount].x = projection.unprojectX(l+lr+.5);
  86. newIntersections[newIntersectionCount].direction = sign(rv[i]-lv[i]);
  87. ++newIntersectionCount;
  88. }
  89. }
  90. }
  91. }
  92. // Sort new intersections
  93. if (newIntersectionCount >= 2) {
  94. if (newIntersections[0].x > newIntersections[1].x)
  95. newIntersections[3] = newIntersections[0], newIntersections[0] = newIntersections[1], newIntersections[1] = newIntersections[3];
  96. if (newIntersectionCount >= 3 && newIntersections[1].x > newIntersections[2].x) {
  97. newIntersections[3] = newIntersections[1], newIntersections[1] = newIntersections[2], newIntersections[2] = newIntersections[3];
  98. if (newIntersections[0].x > newIntersections[1].x)
  99. newIntersections[3] = newIntersections[0], newIntersections[0] = newIntersections[1], newIntersections[1] = newIntersections[3];
  100. }
  101. }
  102. for (int i = 0; i < newIntersectionCount; ++i) {
  103. if ((newIntersections[i].direction > 0) == !inside) {
  104. intersections.push_back(newIntersections[i]);
  105. inside = !inside;
  106. }
  107. }
  108. // Consistency check
  109. float rvScalar = median(rv[0], rv[1], rv[2]);
  110. if ((rvScalar > .5f) != inside && rvScalar != .5f && !intersections.empty()) {
  111. intersections.pop_back();
  112. inside = !inside;
  113. }
  114. }
  115. #ifdef MSDFGEN_USE_CPP11
  116. line.setIntersections((std::vector<Scanline::Intersection> &&) intersections);
  117. #else
  118. line.setIntersections(intersections);
  119. #endif
  120. }
  121. void scanlineSDF(Scanline &line, const BitmapConstRef<float, 3> &sdf, const Projection &projection, double y, bool inverseYAxis) {
  122. scanlineMSDF(line, sdf, projection, y, inverseYAxis);
  123. }
  124. void scanlineSDF(Scanline &line, const BitmapConstRef<float, 4> &sdf, const Projection &projection, double y, bool inverseYAxis) {
  125. scanlineMSDF(line, sdf, projection, y, inverseYAxis);
  126. }
  127. template <int N>
  128. double estimateSDFErrorInner(const BitmapConstRef<float, N> &sdf, const Shape &shape, const Projection &projection, int scanlinesPerRow, FillRule fillRule) {
  129. if (sdf.width <= 1 || sdf.height <= 1 || scanlinesPerRow < 1)
  130. return 0;
  131. double subRowSize = 1./scanlinesPerRow;
  132. double xFrom = projection.unprojectX(.5);
  133. double xTo = projection.unprojectX(sdf.width-.5);
  134. double overlapFactor = 1/(xTo-xFrom);
  135. double error = 0;
  136. Scanline refScanline, sdfScanline;
  137. for (int row = 0; row < sdf.height-1; ++row) {
  138. for (int subRow = 0; subRow < scanlinesPerRow; ++subRow) {
  139. double bt = (subRow+.5)*subRowSize;
  140. double y = projection.unprojectY(row+bt+.5);
  141. shape.scanline(refScanline, y);
  142. scanlineSDF(sdfScanline, sdf, projection, y, shape.inverseYAxis);
  143. error += 1-overlapFactor*Scanline::overlap(refScanline, sdfScanline, xFrom, xTo, fillRule);
  144. }
  145. }
  146. return error/((sdf.height-1)*scanlinesPerRow);
  147. }
  148. double estimateSDFError(const BitmapConstRef<float, 1> &sdf, const Shape &shape, const Projection &projection, int scanlinesPerRow, FillRule fillRule) {
  149. return estimateSDFErrorInner(sdf, shape, projection, scanlinesPerRow, fillRule);
  150. }
  151. double estimateSDFError(const BitmapConstRef<float, 3> &sdf, const Shape &shape, const Projection &projection, int scanlinesPerRow, FillRule fillRule) {
  152. return estimateSDFErrorInner(sdf, shape, projection, scanlinesPerRow, fillRule);
  153. }
  154. double estimateSDFError(const BitmapConstRef<float, 4> &sdf, const Shape &shape, const Projection &projection, int scanlinesPerRow, FillRule fillRule) {
  155. return estimateSDFErrorInner(sdf, shape, projection, scanlinesPerRow, fillRule);
  156. }
  157. // Legacy API
  158. void scanlineSDF(Scanline &line, const BitmapConstRef<float, 1> &sdf, const Vector2 &scale, const Vector2 &translate, bool inverseYAxis, double y) {
  159. scanlineSDF(line, sdf, Projection(scale, translate), y, inverseYAxis);
  160. }
  161. void scanlineSDF(Scanline &line, const BitmapConstRef<float, 3> &sdf, const Vector2 &scale, const Vector2 &translate, bool inverseYAxis, double y) {
  162. scanlineSDF(line, sdf, Projection(scale, translate), y, inverseYAxis);
  163. }
  164. void scanlineSDF(Scanline &line, const BitmapConstRef<float, 4> &sdf, const Vector2 &scale, const Vector2 &translate, bool inverseYAxis, double y) {
  165. scanlineSDF(line, sdf, Projection(scale, translate), y, inverseYAxis);
  166. }
  167. double estimateSDFError(const BitmapConstRef<float, 1> &sdf, const Shape &shape, const Vector2 &scale, const Vector2 &translate, int scanlinesPerRow, FillRule fillRule) {
  168. return estimateSDFError(sdf, shape, Projection(scale, translate), scanlinesPerRow, fillRule);
  169. }
  170. double estimateSDFError(const BitmapConstRef<float, 3> &sdf, const Shape &shape, const Vector2 &scale, const Vector2 &translate, int scanlinesPerRow, FillRule fillRule) {
  171. return estimateSDFError(sdf, shape, Projection(scale, translate), scanlinesPerRow, fillRule);
  172. }
  173. double estimateSDFError(const BitmapConstRef<float, 4> &sdf, const Shape &shape, const Vector2 &scale, const Vector2 &translate, int scanlinesPerRow, FillRule fillRule) {
  174. return estimateSDFError(sdf, shape, Projection(scale, translate), scanlinesPerRow, fillRule);
  175. }
  176. }