瀏覽代碼

Fixed edge deconverge procedure

Chlumsky 1 年之前
父節點
當前提交
7bbdf32289
共有 4 個文件被更改,包括 21 次插入22 次删除
  1. 21 4
      core/Shape.cpp
  2. 0 2
      core/Shape.h
  3. 0 14
      core/edge-segments.cpp
  4. 0 2
      core/edge-segments.h

+ 21 - 4
core/Shape.cpp

@@ -4,6 +4,8 @@
 #include <cstdlib>
 #include "arithmetics.hpp"
 
+#define DECONVERGE_OVERSHOOT 1.11111111111111111 // moves control points slightly more than necessary to account for floating-point errors
+
 namespace msdfgen {
 
 Shape::Shape() : inverseYAxis(false) { }
@@ -39,13 +41,23 @@ bool Shape::validate() const {
     return true;
 }
 
-static void deconvergeEdge(EdgeHolder &edgeHolder, int param) {
+static void deconvergeEdge(EdgeHolder &edgeHolder, int param, Vector2 vector) {
     switch (edgeHolder->type()) {
         case (int) QuadraticSegment::EDGE_TYPE:
             edgeHolder = static_cast<const QuadraticSegment *>(&*edgeHolder)->convertToCubic();
             // fallthrough
         case (int) CubicSegment::EDGE_TYPE:
-            static_cast<CubicSegment *>(&*edgeHolder)->deconverge(param, MSDFGEN_DECONVERGENCE_FACTOR);
+            {
+                Point2 *p = static_cast<CubicSegment *>(&*edgeHolder)->p;
+                switch (param) {
+                    case 0:
+                        p[1] += (p[1]-p[0]).length()*vector;
+                        break;
+                    case 1:
+                        p[2] += (p[2]-p[3]).length()*vector;
+                        break;
+                }
+            }
     }
 }
 
@@ -59,13 +71,18 @@ void Shape::normalize() {
             contour->edges.push_back(EdgeHolder(parts[1]));
             contour->edges.push_back(EdgeHolder(parts[2]));
         } else {
+            // Push apart convergent edge segments
             EdgeHolder *prevEdge = &contour->edges.back();
             for (std::vector<EdgeHolder>::iterator edge = contour->edges.begin(); edge != contour->edges.end(); ++edge) {
                 Vector2 prevDir = (*prevEdge)->direction(1).normalize();
                 Vector2 curDir = (*edge)->direction(0).normalize();
                 if (dotProduct(prevDir, curDir) < MSDFGEN_CORNER_DOT_EPSILON-1) {
-                    deconvergeEdge(*prevEdge, 1);
-                    deconvergeEdge(*edge, 0);
+                    double factor = DECONVERGE_OVERSHOOT*sqrt(1-(MSDFGEN_CORNER_DOT_EPSILON-1)*(MSDFGEN_CORNER_DOT_EPSILON-1))/(MSDFGEN_CORNER_DOT_EPSILON-1);
+                    Vector2 axis = factor*(prevDir-curDir).normalize();
+                    if (crossProduct(2*(*prevEdge)->direction(1)-(*prevEdge)->directionChange(1), 2*(*edge)->direction(0)+(*edge)->directionChange(0)) < 0)
+                        axis = -axis;
+                    deconvergeEdge(*prevEdge, 1, axis.getOrthogonal(true));
+                    deconvergeEdge(*edge, 0, axis.getOrthogonal(false));
                 }
                 prevEdge = &*edge;
             }

+ 0 - 2
core/Shape.h

@@ -9,8 +9,6 @@ namespace msdfgen {
 
 // Threshold of the dot product of adjacent edge directions to be considered convergent.
 #define MSDFGEN_CORNER_DOT_EPSILON .000001
-// The proportional amount by which a curve's control point will be adjusted to eliminate convergent corners.
-#define MSDFGEN_DECONVERGENCE_FACTOR .000001
 
 /// Vector shape representation.
 class Shape {

+ 0 - 14
core/edge-segments.cpp

@@ -524,18 +524,4 @@ EdgeSegment *QuadraticSegment::convertToCubic() const {
     return new CubicSegment(p[0], mix(p[0], p[1], 2/3.), mix(p[1], p[2], 1/3.), p[2], color);
 }
 
-void CubicSegment::deconverge(int param, double amount) {
-    Vector2 dir = direction(param);
-    Vector2 normal = dir.getOrthonormal();
-    double h = dotProduct(directionChange(param)-dir, normal);
-    switch (param) {
-        case 0:
-            p[1] += amount*(dir+sign(h)*sqrt(fabs(h))*normal);
-            break;
-        case 1:
-            p[2] -= amount*(dir-sign(h)*sqrt(fabs(h))*normal);
-            break;
-    }
-}
-
 }

+ 0 - 2
core/edge-segments.h

@@ -141,8 +141,6 @@ public:
     void moveEndPoint(Point2 to);
     void splitInThirds(EdgeSegment *&part0, EdgeSegment *&part1, EdgeSegment *&part2) const;
 
-    void deconverge(int param, double amount);
-
 };
 
 }