sdf-error-estimation.cpp 8.6 KB

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