Browse Source

Edge coloring update, circles no longer white

Chlumsky 1 year ago
parent
commit
35f92541c4
6 changed files with 83 additions and 46 deletions
  1. 1 1
      LICENSE.txt
  2. 7 0
      core/contour-combiners.cpp
  3. 72 42
      core/edge-coloring.cpp
  4. 1 1
      main.cpp
  5. 1 1
      msdfgen-ext.h
  6. 1 1
      msdfgen.h

+ 1 - 1
LICENSE.txt

@@ -1,6 +1,6 @@
 MIT License
 
-Copyright (c) 2016 - 2023 Viktor Chlumsky
+Copyright (c) 2016 - 2024 Viktor Chlumsky
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal

+ 7 - 0
core/contour-combiners.cpp

@@ -16,6 +16,13 @@ static void initDistance(MultiDistance &distance) {
     distance.b = -DBL_MAX;
 }
 
+static void initDistance(MultiAndTrueDistance &distance) {
+    distance.r = -DBL_MAX;
+    distance.g = -DBL_MAX;
+    distance.b = -DBL_MAX;
+    distance.a = -DBL_MAX;
+}
+
 static double resolveDistance(double distance) {
     return distance;
 }

+ 72 - 42
core/edge-coloring.cpp

@@ -11,6 +11,15 @@
 
 namespace msdfgen {
 
+/**
+ * For each position < n, this function will return -1, 0, or 1,
+ * depending on whether the position is closer to the beginning, middle, or end, respectively.
+ * It is guaranteed that the output will be balanced in that the total for positions 0 through n-1 will be zero.
+ */
+static int symmetricalTrichotomy(int position, int n) {
+    return int(3+2.875*position/(n-1)-1.4375+.5)-3;
+}
+
 static bool isCorner(const Vector2 &aDir, const Vector2 &bDir, double crossThreshold) {
     return dotProduct(aDir, bDir) <= 0 || fabs(crossProduct(aDir, bDir)) > crossThreshold;
 }
@@ -26,30 +35,45 @@ static double estimateEdgeLength(const EdgeSegment *edge) {
     return len;
 }
 
-static void switchColor(EdgeColor &color, unsigned long long &seed, EdgeColor banned = BLACK) {
+static int seedExtract2(unsigned long long &seed) {
+    int v = int(seed)&1;
+    seed >>= 1;
+    return v;
+}
+
+static int seedExtract3(unsigned long long &seed) {
+    int v = int(seed%3);
+    seed /= 3;
+    return v;
+}
+
+static EdgeColor initColor(unsigned long long &seed) {
+    static const EdgeColor colors[3] = { CYAN, MAGENTA, YELLOW };
+    return colors[seedExtract3(seed)];
+}
+
+static void switchColor(EdgeColor &color, unsigned long long &seed) {
+    int shifted = color<<(1+seedExtract2(seed));
+    color = EdgeColor((shifted|shifted>>3)&WHITE);
+}
+
+static void switchColor(EdgeColor &color, unsigned long long &seed, EdgeColor banned) {
     EdgeColor combined = EdgeColor(color&banned);
-    if (combined == RED || combined == GREEN || combined == BLUE) {
+    if (combined == RED || combined == GREEN || combined == BLUE)
         color = EdgeColor(combined^WHITE);
-        return;
-    }
-    if (color == BLACK || color == WHITE) {
-        static const EdgeColor start[3] = { CYAN, MAGENTA, YELLOW };
-        color = start[seed%3];
-        seed /= 3;
-        return;
-    }
-    int shifted = color<<(1+(seed&1));
-    color = EdgeColor((shifted|shifted>>3)&WHITE);
-    seed >>= 1;
+    else
+        switchColor(color, seed);
 }
 
 void edgeColoringSimple(Shape &shape, double angleThreshold, unsigned long long seed) {
     double crossThreshold = sin(angleThreshold);
+    EdgeColor color = initColor(seed);
     std::vector<int> corners;
     for (std::vector<Contour>::iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour) {
-        // Identify corners
-        corners.clear();
-        if (!contour->edges.empty()) {
+        if (contour->edges.empty())
+            continue;
+        { // Identify corners
+            corners.clear();
             Vector2 prevDirection = contour->edges.back()->direction(1);
             int index = 0;
             for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge, ++index) {
@@ -60,19 +84,24 @@ void edgeColoringSimple(Shape &shape, double angleThreshold, unsigned long long
         }
 
         // Smooth contour
-        if (corners.empty())
+        if (corners.empty()) {
+            switchColor(color, seed);
             for (std::vector<EdgeHolder>::iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge)
-                (*edge)->color = WHITE;
+                (*edge)->color = color;
+        }
         // "Teardrop" case
         else if (corners.size() == 1) {
-            EdgeColor colors[3] = { WHITE, WHITE };
-            switchColor(colors[0], seed);
-            switchColor(colors[2] = colors[0], seed);
+            EdgeColor colors[3];
+            switchColor(color, seed);
+            colors[0] = color;
+            colors[1] = WHITE;
+            switchColor(color, seed);
+            colors[2] = color;
             int corner = corners[0];
             if (contour->edges.size() >= 3) {
                 int m = (int) contour->edges.size();
                 for (int i = 0; i < m; ++i)
-                    contour->edges[(corner+i)%m]->color = (colors+1)[int(3+2.875*i/(m-1)-1.4375+.5)-3];
+                    contour->edges[(corner+i)%m]->color = colors[1+symmetricalTrichotomy(i, m)];
             } else if (contour->edges.size() >= 1) {
                 // Less than three edge segments for three colors => edges must be split
                 EdgeSegment *parts[7] = { };
@@ -98,7 +127,6 @@ void edgeColoringSimple(Shape &shape, double angleThreshold, unsigned long long
             int spline = 0;
             int start = corners[0];
             int m = (int) contour->edges.size();
-            EdgeColor color = WHITE;
             switchColor(color, seed);
             EdgeColor initialColor = color;
             for (int i = 0; i < m; ++i) {
@@ -123,12 +151,14 @@ struct EdgeColoringInkTrapCorner {
 void edgeColoringInkTrap(Shape &shape, double angleThreshold, unsigned long long seed) {
     typedef EdgeColoringInkTrapCorner Corner;
     double crossThreshold = sin(angleThreshold);
+    EdgeColor color = initColor(seed);
     std::vector<Corner> corners;
     for (std::vector<Contour>::iterator contour = shape.contours.begin(); contour != shape.contours.end(); ++contour) {
-        // Identify corners
+        if (contour->edges.empty())
+            continue;
         double splineLength = 0;
-        corners.clear();
-        if (!contour->edges.empty()) {
+        { // Identify corners
+            corners.clear();
             Vector2 prevDirection = contour->edges.back()->direction(1);
             int index = 0;
             for (std::vector<EdgeHolder>::const_iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge, ++index) {
@@ -143,19 +173,24 @@ void edgeColoringInkTrap(Shape &shape, double angleThreshold, unsigned long long
         }
 
         // Smooth contour
-        if (corners.empty())
+        if (corners.empty()) {
+            switchColor(color, seed);
             for (std::vector<EdgeHolder>::iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge)
-                (*edge)->color = WHITE;
+                (*edge)->color = color;
+        }
         // "Teardrop" case
         else if (corners.size() == 1) {
-            EdgeColor colors[3] = { WHITE, WHITE };
-            switchColor(colors[0], seed);
-            switchColor(colors[2] = colors[0], seed);
+            EdgeColor colors[3];
+            switchColor(color, seed);
+            colors[0] = color;
+            colors[1] = WHITE;
+            switchColor(color, seed);
+            colors[2] = color;
             int corner = corners[0].index;
             if (contour->edges.size() >= 3) {
                 int m = (int) contour->edges.size();
                 for (int i = 0; i < m; ++i)
-                    contour->edges[(corner+i)%m]->color = (colors+1)[int(3+2.875*i/(m-1)-1.4375+.5)-3];
+                    contour->edges[(corner+i)%m]->color = colors[1+symmetricalTrichotomy(i, m)];
             } else if (contour->edges.size() >= 1) {
                 // Less than three edge segments for three colors => edges must be split
                 EdgeSegment *parts[7] = { };
@@ -191,7 +226,6 @@ void edgeColoringInkTrap(Shape &shape, double angleThreshold, unsigned long long
                     }
                 }
             }
-            EdgeColor color = WHITE;
             EdgeColor initialColor = BLACK;
             for (int i = 0; i < cornerCount; ++i) {
                 if (!corners[i].minor) {
@@ -271,23 +305,19 @@ static void colorSecondDegreeGraph(int *coloring, const int *const *edgeMatrix,
                 color = 1;
                 break;
             case 3:
-                color = (int) seed&1;
-                seed >>= 1;
+                color = seedExtract2(seed); // 0 or 1
                 break;
             case 4:
                 color = 2;
                 break;
             case 5:
-                color = ((int) seed+1&1)<<1;
-                seed >>= 1;
+                color = (int) !seedExtract2(seed)<<1; // 2 or 0
                 break;
             case 6:
-                color = ((int) seed&1)+1;
-                seed >>= 1;
+                color = seedExtract2(seed)+1; // 1 or 2
                 break;
             case 7:
-                color = int((seed+i)%3);
-                seed /= 3;
+                color = (seedExtract3(seed)+i)%3; // 0 or 1 or 2
                 break;
         }
         coloring[i] = color;
@@ -394,7 +424,7 @@ void edgeColoringByDistance(Shape &shape, double angleThreshold, unsigned long l
                     for (int i = 0; i < m; ++i) {
                         if (i == m/2)
                             splineStarts.push_back((int) edgeSegments.size());
-                        if (int(3+2.875*i/(m-1)-1.4375+.5)-3)
+                        if (symmetricalTrichotomy(i, m))
                             edgeSegments.push_back(&*contour->edges[(corner+i)%m]);
                         else
                             contour->edges[(corner+i)%m]->color = WHITE;

+ 1 - 1
main.cpp

@@ -2,7 +2,7 @@
 /*
  * MULTI-CHANNEL SIGNED DISTANCE FIELD GENERATOR - standalone console program
  * --------------------------------------------------------------------------
- * A utility by Viktor Chlumsky, (c) 2014 - 2023
+ * A utility by Viktor Chlumsky, (c) 2014 - 2024
  *
  */
 

+ 1 - 1
msdfgen-ext.h

@@ -4,7 +4,7 @@
 /*
  * MULTI-CHANNEL SIGNED DISTANCE FIELD GENERATOR
  * ---------------------------------------------
- * A utility by Viktor Chlumsky, (c) 2014 - 2023
+ * A utility by Viktor Chlumsky, (c) 2014 - 2024
  *
  * The extension module provides ways to easily load input and save output using popular formats.
  *

+ 1 - 1
msdfgen.h

@@ -4,7 +4,7 @@
 /*
  * MULTI-CHANNEL SIGNED DISTANCE FIELD GENERATOR
  * ---------------------------------------------
- * A utility by Viktor Chlumsky, (c) 2014 - 2023
+ * A utility by Viktor Chlumsky, (c) 2014 - 2024
  *
  * The technique used to generate multi-channel distance fields in this code
  * has been developed by Viktor Chlumsky in 2014 for his master's thesis,