2
0

Shape.cpp 8.3 KB

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