Shape.cpp 7.4 KB

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