edge-coloring.cpp 4.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  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 void switchColor(EdgeColor &color, unsigned long long &seed, EdgeColor banned = BLACK) {
  7. EdgeColor combined = EdgeColor(color&banned);
  8. if (combined == RED || combined == GREEN || combined == BLUE) {
  9. color = EdgeColor(combined^WHITE);
  10. return;
  11. }
  12. if (color == BLACK || color == WHITE) {
  13. static const EdgeColor start[3] = { CYAN, MAGENTA, YELLOW };
  14. color = start[seed%3];
  15. seed /= 3;
  16. return;
  17. }
  18. int shifted = color<<(1+(seed&1));
  19. color = EdgeColor((shifted|shifted>>3)&WHITE);
  20. seed >>= 1;
  21. }
  22. void edgeColoringSimple(Shape &shape, double angleThreshold, unsigned long long seed) {
  23. double crossThreshold = sin(angleThreshold);
  24. std::vector<int> corners;
  25. for (std::vector<Contour>::iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour) {
  26. // Identify corners
  27. corners.clear();
  28. if (!contour->edges.empty()) {
  29. Vector2 prevDirection = contour->edges.back()->direction(1);
  30. int index = 0;
  31. for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge, ++index) {
  32. if (isCorner(prevDirection.normalize(), (*edge)->direction(0).normalize(), crossThreshold))
  33. corners.push_back(index);
  34. prevDirection = (*edge)->direction(1);
  35. }
  36. }
  37. // Smooth contour
  38. if (corners.empty())
  39. for (std::vector<EdgeHolder>::iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge)
  40. (*edge)->color = WHITE;
  41. // "Teardrop" case
  42. else if (corners.size() == 1) {
  43. EdgeColor colors[3] = { WHITE, WHITE };
  44. switchColor(colors[0], seed);
  45. switchColor(colors[2] = colors[0], seed);
  46. int corner = corners[0];
  47. if (contour->edges.size() >= 3) {
  48. int m = (int) contour->edges.size();
  49. for (int i = 0; i < m; ++i)
  50. contour->edges[(corner+i)%m]->color = (colors+1)[int(3+2.875*i/(m-1)-1.4375+.5)-3];
  51. } else if (contour->edges.size() >= 1) {
  52. // Less than three edge segments for three colors => edges must be split
  53. EdgeSegment *parts[7] = { };
  54. contour->edges[0]->splitInThirds(parts[0+3*corner], parts[1+3*corner], parts[2+3*corner]);
  55. if (contour->edges.size() >= 2) {
  56. contour->edges[1]->splitInThirds(parts[3-3*corner], parts[4-3*corner], parts[5-3*corner]);
  57. parts[0]->color = parts[1]->color = colors[0];
  58. parts[2]->color = parts[3]->color = colors[1];
  59. parts[4]->color = parts[5]->color = colors[2];
  60. } else {
  61. parts[0]->color = colors[0];
  62. parts[1]->color = colors[1];
  63. parts[2]->color = colors[2];
  64. }
  65. contour->edges.clear();
  66. for (int i = 0; parts[i]; ++i)
  67. contour->edges.push_back(EdgeHolder(parts[i]));
  68. }
  69. }
  70. // Multiple corners
  71. else {
  72. int cornerCount = (int) corners.size();
  73. int spline = 0;
  74. int start = corners[0];
  75. int m = (int) contour->edges.size();
  76. EdgeColor color = WHITE;
  77. switchColor(color, seed);
  78. EdgeColor initialColor = color;
  79. for (int i = 0; i < m; ++i) {
  80. int index = (start+i)%m;
  81. if (spline+1 < cornerCount && corners[spline+1] == index) {
  82. ++spline;
  83. switchColor(color, seed, EdgeColor((spline == cornerCount-1)*initialColor));
  84. }
  85. contour->edges[index]->color = color;
  86. }
  87. }
  88. }
  89. }
  90. }