2
0

Shape.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. #include "Shape.h"
  2. #include <cstdlib>
  3. #include <cfloat>
  4. #include "arithmetics.hpp"
  5. namespace msdfgen {
  6. Shape::Shape() : inverseYAxis(false) { }
  7. void Shape::addContour(const Contour &contour) {
  8. contours.push_back(contour);
  9. }
  10. #ifdef MSDFGEN_USE_CPP11
  11. void Shape::addContour(Contour &&contour) {
  12. contours.push_back((Contour &&) contour);
  13. }
  14. #endif
  15. Contour &Shape::addContour() {
  16. contours.resize(contours.size()+1);
  17. return contours.back();
  18. }
  19. bool Shape::validate() const {
  20. for (std::vector<Contour>::const_iterator contour = contours.begin(); contour != contours.end(); ++contour) {
  21. if (!contour->edges.empty()) {
  22. Point2 corner = contour->edges.back()->point(1);
  23. for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) {
  24. if (!*edge)
  25. return false;
  26. if ((*edge)->point(0) != corner)
  27. return false;
  28. corner = (*edge)->point(1);
  29. }
  30. }
  31. }
  32. return true;
  33. }
  34. static void deconvergeEdge(EdgeHolder &edgeHolder, int param) {
  35. switch (edgeHolder->type()) {
  36. case (int) QuadraticSegment::EDGE_TYPE:
  37. edgeHolder = static_cast<const QuadraticSegment *>(&*edgeHolder)->convertToCubic();
  38. // fallthrough
  39. case (int) CubicSegment::EDGE_TYPE:
  40. static_cast<CubicSegment *>(&*edgeHolder)->deconverge(param, MSDFGEN_DECONVERGENCE_FACTOR);
  41. }
  42. }
  43. void Shape::normalize() {
  44. for (std::vector<Contour>::iterator contour = contours.begin(); contour != contours.end(); ++contour) {
  45. if (contour->edges.size() == 1) {
  46. EdgeSegment *parts[3] = { };
  47. contour->edges[0]->splitInThirds(parts[0], parts[1], parts[2]);
  48. contour->edges.clear();
  49. contour->edges.push_back(EdgeHolder(parts[0]));
  50. contour->edges.push_back(EdgeHolder(parts[1]));
  51. contour->edges.push_back(EdgeHolder(parts[2]));
  52. } else {
  53. EdgeHolder *prevEdge = &contour->edges.back();
  54. for (std::vector<EdgeHolder>::iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) {
  55. Vector2 prevDir = (*prevEdge)->direction(1).normalize();
  56. Vector2 curDir = (*edge)->direction(0).normalize();
  57. if (dotProduct(prevDir, curDir) < MSDFGEN_CORNER_DOT_EPSILON-real(1)) {
  58. deconvergeEdge(*prevEdge, 1);
  59. deconvergeEdge(*edge, 0);
  60. }
  61. prevEdge = &*edge;
  62. }
  63. }
  64. }
  65. }
  66. void Shape::bound(real &l, real &b, real &r, real &t) const {
  67. for (std::vector<Contour>::const_iterator contour = contours.begin(); contour != contours.end(); ++contour)
  68. contour->bound(l, b, r, t);
  69. }
  70. void Shape::boundMiters(real &l, real &b, real &r, real &t, real border, real miterLimit, int polarity) const {
  71. for (std::vector<Contour>::const_iterator contour = contours.begin(); contour != contours.end(); ++contour)
  72. contour->boundMiters(l, b, r, t, border, miterLimit, polarity);
  73. }
  74. Shape::Bounds Shape::getBounds(real border, real miterLimit, int polarity) const {
  75. Shape::Bounds bounds = { +FLT_MAX, +FLT_MAX, -FLT_MAX, -FLT_MAX };
  76. bound(bounds.l, bounds.b, bounds.r, bounds.t);
  77. if (border > real(0)) {
  78. bounds.l -= border, bounds.b -= border;
  79. bounds.r += border, bounds.t += border;
  80. if (miterLimit > real(0))
  81. boundMiters(bounds.l, bounds.b, bounds.r, bounds.t, border, miterLimit, polarity);
  82. }
  83. return bounds;
  84. }
  85. void Shape::scanline(Scanline &line, real y) const {
  86. std::vector<Scanline::Intersection> intersections;
  87. real x[3];
  88. int dy[3];
  89. for (std::vector<Contour>::const_iterator contour = contours.begin(); contour != contours.end(); ++contour) {
  90. for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) {
  91. int n = (*edge)->scanlineIntersections(x, dy, y);
  92. for (int i = 0; i < n; ++i) {
  93. Scanline::Intersection intersection = { x[i], dy[i] };
  94. intersections.push_back(intersection);
  95. }
  96. }
  97. }
  98. #ifdef MSDFGEN_USE_CPP11
  99. line.setIntersections((std::vector<Scanline::Intersection> &&) intersections);
  100. #else
  101. line.setIntersections(intersections);
  102. #endif
  103. }
  104. int Shape::edgeCount() const {
  105. int total = 0;
  106. for (std::vector<Contour>::const_iterator contour = contours.begin(); contour != contours.end(); ++contour)
  107. total += (int) contour->edges.size();
  108. return total;
  109. }
  110. void Shape::orientContours() {
  111. struct Intersection {
  112. real x;
  113. int direction;
  114. int contourIndex;
  115. static int compare(const void *a, const void *b) {
  116. return sign(reinterpret_cast<const Intersection *>(a)->x-reinterpret_cast<const Intersection *>(b)->x);
  117. }
  118. };
  119. const real ratio = real(.5)*(sqrt(5)-real(1)); // an irrational number to minimize chance of intersecting a corner or other point of interest
  120. std::vector<int> orientations(contours.size());
  121. std::vector<Intersection> intersections;
  122. for (int i = 0; i < (int) contours.size(); ++i) {
  123. if (!orientations[i] && !contours[i].edges.empty()) {
  124. // Find an Y that crosses the contour
  125. real y0 = contours[i].edges.front()->point(0).y;
  126. real y1 = y0;
  127. for (std::vector<EdgeHolder>::const_iterator edge = contours[i].edges.begin(); edge != contours[i].edges.end() && y0 == y1; ++edge)
  128. y1 = (*edge)->point(1).y;
  129. for (std::vector<EdgeHolder>::const_iterator edge = contours[i].edges.begin(); edge != contours[i].edges.end() && y0 == y1; ++edge)
  130. y1 = (*edge)->point(ratio).y; // in case all endpoints are in a horizontal line
  131. real y = mix(y0, y1, ratio);
  132. // Scanline through whole shape at Y
  133. real x[3];
  134. int dy[3];
  135. for (int j = 0; j < (int) contours.size(); ++j) {
  136. for (std::vector<EdgeHolder>::const_iterator edge = contours[j].edges.begin(); edge != contours[j].edges.end(); ++edge) {
  137. int n = (*edge)->scanlineIntersections(x, dy, y);
  138. for (int k = 0; k < n; ++k) {
  139. Intersection intersection = { x[k], dy[k], j };
  140. intersections.push_back(intersection);
  141. }
  142. }
  143. }
  144. if (!intersections.empty()) {
  145. qsort(&intersections[0], intersections.size(), sizeof(Intersection), &Intersection::compare);
  146. // Disqualify multiple intersections
  147. for (int j = 1; j < (int) intersections.size(); ++j)
  148. if (intersections[j].x == intersections[j-1].x)
  149. intersections[j].direction = intersections[j-1].direction = 0;
  150. // Inspect scanline and deduce orientations of intersected contours
  151. for (int j = 0; j < (int) intersections.size(); ++j)
  152. if (intersections[j].direction)
  153. orientations[intersections[j].contourIndex] += 2*((j&1)^(intersections[j].direction > 0))-1;
  154. intersections.clear();
  155. }
  156. }
  157. }
  158. // Reverse contours that have the opposite orientation
  159. for (int i = 0; i < (int) contours.size(); ++i)
  160. if (orientations[i] < 0)
  161. contours[i].reverse();
  162. }
  163. }