edge-coloring.cpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. #include "edge-coloring.h"
  2. namespace msdfgen {
  3. static bool isCorner(const Vector2 &aDir, const Vector2 &bDir, double crossThreshold) {
  4. return dotProduct(aDir, bDir) <= 0 || fabs(crossProduct(aDir, bDir)) > crossThreshold;
  5. }
  6. static double estimateEdgeLength(const EdgeSegment *edge) {
  7. double len = 0;
  8. Point2 prev = edge->point(0);
  9. for (int i = 1; i <= MSDFGEN_EDGE_LENGTH_PRECISION; ++i) {
  10. Point2 cur = edge->point(1./MSDFGEN_EDGE_LENGTH_PRECISION*i);
  11. len += (cur-prev).length();
  12. prev = cur;
  13. }
  14. return len;
  15. }
  16. static void switchColor(EdgeColor &color, unsigned long long &seed, EdgeColor banned = BLACK) {
  17. EdgeColor combined = EdgeColor(color&banned);
  18. if (combined == RED || combined == GREEN || combined == BLUE) {
  19. color = EdgeColor(combined^WHITE);
  20. return;
  21. }
  22. if (color == BLACK || color == WHITE) {
  23. static const EdgeColor start[3] = { CYAN, MAGENTA, YELLOW };
  24. color = start[seed%3];
  25. seed /= 3;
  26. return;
  27. }
  28. int shifted = color<<(1+(seed&1));
  29. color = EdgeColor((shifted|shifted>>3)&WHITE);
  30. seed >>= 1;
  31. }
  32. void edgeColoringSimple(Shape &shape, double angleThreshold, unsigned long long seed) {
  33. double crossThreshold = sin(angleThreshold);
  34. std::vector<int> corners;
  35. for (std::vector<Contour>::iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour) {
  36. // Identify corners
  37. corners.clear();
  38. if (!contour->edges.empty()) {
  39. Vector2 prevDirection = contour->edges.back()->direction(1);
  40. int index = 0;
  41. for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge, ++index) {
  42. if (isCorner(prevDirection.normalize(), (*edge)->direction(0).normalize(), crossThreshold))
  43. corners.push_back(index);
  44. prevDirection = (*edge)->direction(1);
  45. }
  46. }
  47. // Smooth contour
  48. if (corners.empty())
  49. for (std::vector<EdgeHolder>::iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge)
  50. (*edge)->color = WHITE;
  51. // "Teardrop" case
  52. else if (corners.size() == 1) {
  53. EdgeColor colors[3] = { WHITE, WHITE };
  54. switchColor(colors[0], seed);
  55. switchColor(colors[2] = colors[0], seed);
  56. int corner = corners[0];
  57. if (contour->edges.size() >= 3) {
  58. int m = (int) contour->edges.size();
  59. for (int i = 0; i < m; ++i)
  60. contour->edges[(corner+i)%m]->color = (colors+1)[int(3+2.875*i/(m-1)-1.4375+.5)-3];
  61. } else if (contour->edges.size() >= 1) {
  62. // Less than three edge segments for three colors => edges must be split
  63. EdgeSegment *parts[7] = { };
  64. contour->edges[0]->splitInThirds(parts[0+3*corner], parts[1+3*corner], parts[2+3*corner]);
  65. if (contour->edges.size() >= 2) {
  66. contour->edges[1]->splitInThirds(parts[3-3*corner], parts[4-3*corner], parts[5-3*corner]);
  67. parts[0]->color = parts[1]->color = colors[0];
  68. parts[2]->color = parts[3]->color = colors[1];
  69. parts[4]->color = parts[5]->color = colors[2];
  70. } else {
  71. parts[0]->color = colors[0];
  72. parts[1]->color = colors[1];
  73. parts[2]->color = colors[2];
  74. }
  75. contour->edges.clear();
  76. for (int i = 0; parts[i]; ++i)
  77. contour->edges.push_back(EdgeHolder(parts[i]));
  78. }
  79. }
  80. // Multiple corners
  81. else {
  82. int cornerCount = (int) corners.size();
  83. int spline = 0;
  84. int start = corners[0];
  85. int m = (int) contour->edges.size();
  86. EdgeColor color = WHITE;
  87. switchColor(color, seed);
  88. EdgeColor initialColor = color;
  89. for (int i = 0; i < m; ++i) {
  90. int index = (start+i)%m;
  91. if (spline+1 < cornerCount && corners[spline+1] == index) {
  92. ++spline;
  93. switchColor(color, seed, EdgeColor((spline == cornerCount-1)*initialColor));
  94. }
  95. contour->edges[index]->color = color;
  96. }
  97. }
  98. }
  99. }
  100. struct EdgeColoringInkTrapCorner {
  101. int index;
  102. double prevEdgeLengthEstimate;
  103. bool minor;
  104. EdgeColor color;
  105. };
  106. void edgeColoringInkTrap(Shape &shape, double angleThreshold, unsigned long long seed) {
  107. typedef EdgeColoringInkTrapCorner Corner;
  108. double crossThreshold = sin(angleThreshold);
  109. std::vector<Corner> corners;
  110. for (std::vector<Contour>::iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour) {
  111. // Identify corners
  112. double splineLength = 0;
  113. corners.clear();
  114. if (!contour->edges.empty()) {
  115. Vector2 prevDirection = contour->edges.back()->direction(1);
  116. int index = 0;
  117. for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge, ++index) {
  118. if (isCorner(prevDirection.normalize(), (*edge)->direction(0).normalize(), crossThreshold)) {
  119. Corner corner = { index, splineLength };
  120. corners.push_back(corner);
  121. splineLength = 0;
  122. }
  123. splineLength += estimateEdgeLength(*edge);
  124. prevDirection = (*edge)->direction(1);
  125. }
  126. }
  127. // Smooth contour
  128. if (corners.empty())
  129. for (std::vector<EdgeHolder>::iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge)
  130. (*edge)->color = WHITE;
  131. // "Teardrop" case
  132. else if (corners.size() == 1) {
  133. EdgeColor colors[3] = { WHITE, WHITE };
  134. switchColor(colors[0], seed);
  135. switchColor(colors[2] = colors[0], seed);
  136. int corner = corners[0].index;
  137. if (contour->edges.size() >= 3) {
  138. int m = (int) contour->edges.size();
  139. for (int i = 0; i < m; ++i)
  140. contour->edges[(corner+i)%m]->color = (colors+1)[int(3+2.875*i/(m-1)-1.4375+.5)-3];
  141. } else if (contour->edges.size() >= 1) {
  142. // Less than three edge segments for three colors => edges must be split
  143. EdgeSegment *parts[7] = { };
  144. contour->edges[0]->splitInThirds(parts[0+3*corner], parts[1+3*corner], parts[2+3*corner]);
  145. if (contour->edges.size() >= 2) {
  146. contour->edges[1]->splitInThirds(parts[3-3*corner], parts[4-3*corner], parts[5-3*corner]);
  147. parts[0]->color = parts[1]->color = colors[0];
  148. parts[2]->color = parts[3]->color = colors[1];
  149. parts[4]->color = parts[5]->color = colors[2];
  150. } else {
  151. parts[0]->color = colors[0];
  152. parts[1]->color = colors[1];
  153. parts[2]->color = colors[2];
  154. }
  155. contour->edges.clear();
  156. for (int i = 0; parts[i]; ++i)
  157. contour->edges.push_back(EdgeHolder(parts[i]));
  158. }
  159. }
  160. // Multiple corners
  161. else {
  162. int cornerCount = (int) corners.size();
  163. int majorCornerCount = cornerCount;
  164. if (cornerCount > 3) {
  165. corners.begin()->prevEdgeLengthEstimate += splineLength;
  166. for (int i = 0; i < cornerCount; ++i) {
  167. if (
  168. corners[i].prevEdgeLengthEstimate > corners[(i+1)%cornerCount].prevEdgeLengthEstimate &&
  169. corners[(i+1)%cornerCount].prevEdgeLengthEstimate < corners[(i+2)%cornerCount].prevEdgeLengthEstimate
  170. ) {
  171. corners[i].minor = true;
  172. --majorCornerCount;
  173. }
  174. }
  175. }
  176. EdgeColor color = WHITE;
  177. EdgeColor initialColor = BLACK;
  178. for (int i = 0; i < cornerCount; ++i) {
  179. if (!corners[i].minor) {
  180. --majorCornerCount;
  181. switchColor(color, seed, EdgeColor(!majorCornerCount*initialColor));
  182. corners[i].color = color;
  183. if (!initialColor)
  184. initialColor = color;
  185. }
  186. }
  187. for (int i = 0; i < cornerCount; ++i) {
  188. if (corners[i].minor) {
  189. EdgeColor nextColor = corners[(i+1)%cornerCount].color;
  190. corners[i].color = EdgeColor((color&nextColor)^WHITE);
  191. } else
  192. color = corners[i].color;
  193. }
  194. int spline = 0;
  195. int start = corners[0].index;
  196. color = corners[0].color;
  197. int m = (int) contour->edges.size();
  198. for (int i = 0; i < m; ++i) {
  199. int index = (start+i)%m;
  200. if (spline+1 < cornerCount && corners[spline+1].index == index)
  201. color = corners[++spline].color;
  202. contour->edges[index]->color = color;
  203. }
  204. }
  205. }
  206. }
  207. }