Browse Source

Renamed pseudo-distance to perpendicular distance

Chlumsky 1 year ago
parent
commit
64c3e24829
10 changed files with 129 additions and 111 deletions
  1. 5 6
      README.md
  2. 1 1
      core/MSDFErrorCorrection.cpp
  3. 2 2
      core/contour-combiners.cpp
  4. 7 7
      core/edge-segments.cpp
  5. 2 2
      core/edge-segments.h
  6. 51 51
      core/edge-selectors.cpp
  7. 14 14
      core/edge-selectors.h
  8. 24 12
      core/msdfgen.cpp
  9. 17 14
      main.cpp
  10. 6 2
      msdfgen.h

+ 5 - 6
README.md

@@ -4,7 +4,7 @@ This is a utility for generating signed distance fields from vector shapes and f
 which serve as a texture representation that can be used in real-time graphics to efficiently reproduce said shapes.
 which serve as a texture representation that can be used in real-time graphics to efficiently reproduce said shapes.
 Although it can also be used to generate conventional signed distance fields best known from
 Although it can also be used to generate conventional signed distance fields best known from
 [this Valve paper](https://steamcdn-a.akamaihd.net/apps/valve/2007/SIGGRAPH2007_AlphaTestedMagnification.pdf)
 [this Valve paper](https://steamcdn-a.akamaihd.net/apps/valve/2007/SIGGRAPH2007_AlphaTestedMagnification.pdf)
-and pseudo-distance fields, its primary purpose is to generate multi-channel distance fields,
+and perpendicular distance fields, its primary purpose is to generate multi-channel distance fields,
 using a method I have developed. Unlike monochrome distance fields, they have the ability
 using a method I have developed. Unlike monochrome distance fields, they have the ability
 to reproduce sharp corners almost perfectly by utilizing all three color channels.
 to reproduce sharp corners almost perfectly by utilizing all three color channels.
 
 
@@ -52,7 +52,7 @@ where only the input specification is required.
 
 
 Mode can be one of:
 Mode can be one of:
  - **sdf** – generates a conventional monochrome (true) signed distance field.
  - **sdf** – generates a conventional monochrome (true) signed distance field.
- - **psdf** – generates a monochrome signed pseudo-distance field.
+ - **psdf** – generates a monochrome signed perpendicular distance field.
  - **msdf** (default) – generates a multi-channel signed distance field using my new method.
  - **msdf** (default) – generates a multi-channel signed distance field using my new method.
  - **mtsdf** – generates a combined multi-channel and true signed distance field in the alpha channel.
  - **mtsdf** – generates a combined multi-channel and true signed distance field in the alpha channel.
 
 
@@ -104,10 +104,9 @@ in order to generate a distance field. Please note that all classes and function
    It consists of closed contours, which in turn consist of edges. An edge is represented by a `LinearEdge`, `QuadraticEdge`,
    It consists of closed contours, which in turn consist of edges. An edge is represented by a `LinearEdge`, `QuadraticEdge`,
    or `CubicEdge`. You can construct them from two endpoints and 0 to 2 Bézier control points.
    or `CubicEdge`. You can construct them from two endpoints and 0 to 2 Bézier control points.
  - Normalize the shape using its `normalize` method and assign colors to edges if you need a multi-channel SDF.
  - Normalize the shape using its `normalize` method and assign colors to edges if you need a multi-channel SDF.
-   This can be performed automatically using the `edgeColoringSimple` heuristic, or manually by setting each edge's
-   `color` member. Keep in mind that at least two color channels must be turned on in each edge, and iff two edges meet
-   at a sharp corner, they must only have one channel in common.
- - Call `generateSDF`, `generatePseudoSDF`, or `generateMSDF` to generate a distance field into a floating point
+   This can be performed automatically using the `edgeColoringSimple` (or other) heuristic, or manually by setting each edge's
+   `color` member. Keep in mind that at least two color channels must be turned on in each edge.
+ - Call `generateSDF`, `generatePSDF`, `generateMSDF`, or `generateMTSDF` to generate a distance field into a floating point
    `Bitmap` object. This can then be worked with further or saved to a file using `saveBmp`, `savePng`, or `saveTiff`.
    `Bitmap` object. This can then be worked with further or saved to a file using `saveBmp`, `savePng`, or `saveTiff`.
  - You may also render an image from the distance field using `renderSDF`. Consider calling `simulate8bit`
  - You may also render an image from the distance field using `renderSDF`. Consider calling `simulate8bit`
    on the distance field beforehand to simulate the standard 8 bits/channel image format.
    on the distance field beforehand to simulate the standard 8 bits/channel image format.

+ 1 - 1
core/MSDFErrorCorrection.cpp

@@ -94,7 +94,7 @@ public:
         return ArtifactClassifier(this, direction, span);
         return ArtifactClassifier(this, direction, span);
     }
     }
 private:
 private:
-    ShapeDistanceFinder<ContourCombiner<PseudoDistanceSelector> > distanceFinder;
+    ShapeDistanceFinder<ContourCombiner<PerpendicularDistanceSelector> > distanceFinder;
     BitmapConstRef<float, N> sdf;
     BitmapConstRef<float, N> sdf;
     double invRange;
     double invRange;
     Vector2 texelSize;
     Vector2 texelSize;

+ 2 - 2
core/contour-combiners.cpp

@@ -50,7 +50,7 @@ typename SimpleContourCombiner<EdgeSelector>::DistanceType SimpleContourCombiner
 }
 }
 
 
 template class SimpleContourCombiner<TrueDistanceSelector>;
 template class SimpleContourCombiner<TrueDistanceSelector>;
-template class SimpleContourCombiner<PseudoDistanceSelector>;
+template class SimpleContourCombiner<PerpendicularDistanceSelector>;
 template class SimpleContourCombiner<MultiDistanceSelector>;
 template class SimpleContourCombiner<MultiDistanceSelector>;
 template class SimpleContourCombiner<MultiAndTrueDistanceSelector>;
 template class SimpleContourCombiner<MultiAndTrueDistanceSelector>;
 
 
@@ -134,7 +134,7 @@ typename OverlappingContourCombiner<EdgeSelector>::DistanceType OverlappingConto
 }
 }
 
 
 template class OverlappingContourCombiner<TrueDistanceSelector>;
 template class OverlappingContourCombiner<TrueDistanceSelector>;
-template class OverlappingContourCombiner<PseudoDistanceSelector>;
+template class OverlappingContourCombiner<PerpendicularDistanceSelector>;
 template class OverlappingContourCombiner<MultiDistanceSelector>;
 template class OverlappingContourCombiner<MultiDistanceSelector>;
 template class OverlappingContourCombiner<MultiAndTrueDistanceSelector>;
 template class OverlappingContourCombiner<MultiAndTrueDistanceSelector>;
 
 

+ 7 - 7
core/edge-segments.cpp

@@ -25,15 +25,15 @@ EdgeSegment *EdgeSegment::create(Point2 p0, Point2 p1, Point2 p2, Point2 p3, Edg
     return new CubicSegment(p0, p1, p2, p3, edgeColor);
     return new CubicSegment(p0, p1, p2, p3, edgeColor);
 }
 }
 
 
-void EdgeSegment::distanceToPseudoDistance(SignedDistance &distance, Point2 origin, double param) const {
+void EdgeSegment::distanceToPerpendicularDistance(SignedDistance &distance, Point2 origin, double param) const {
     if (param < 0) {
     if (param < 0) {
         Vector2 dir = direction(0).normalize();
         Vector2 dir = direction(0).normalize();
         Vector2 aq = origin-point(0);
         Vector2 aq = origin-point(0);
         double ts = dotProduct(aq, dir);
         double ts = dotProduct(aq, dir);
         if (ts < 0) {
         if (ts < 0) {
-            double pseudoDistance = crossProduct(aq, dir);
-            if (fabs(pseudoDistance) <= fabs(distance.distance)) {
-                distance.distance = pseudoDistance;
+            double perpendicularDistance = crossProduct(aq, dir);
+            if (fabs(perpendicularDistance) <= fabs(distance.distance)) {
+                distance.distance = perpendicularDistance;
                 distance.dot = 0;
                 distance.dot = 0;
             }
             }
         }
         }
@@ -42,9 +42,9 @@ void EdgeSegment::distanceToPseudoDistance(SignedDistance &distance, Point2 orig
         Vector2 bq = origin-point(1);
         Vector2 bq = origin-point(1);
         double ts = dotProduct(bq, dir);
         double ts = dotProduct(bq, dir);
         if (ts > 0) {
         if (ts > 0) {
-            double pseudoDistance = crossProduct(bq, dir);
-            if (fabs(pseudoDistance) <= fabs(distance.distance)) {
-                distance.distance = pseudoDistance;
+            double perpendicularDistance = crossProduct(bq, dir);
+            if (fabs(perpendicularDistance) <= fabs(distance.distance)) {
+                distance.distance = perpendicularDistance;
                 distance.dot = 0;
                 distance.dot = 0;
             }
             }
         }
         }

+ 2 - 2
core/edge-segments.h

@@ -37,8 +37,8 @@ public:
     virtual Vector2 directionChange(double param) const = 0;
     virtual Vector2 directionChange(double param) const = 0;
     /// Returns the minimum signed distance between origin and the edge.
     /// Returns the minimum signed distance between origin and the edge.
     virtual SignedDistance signedDistance(Point2 origin, double &param) const = 0;
     virtual SignedDistance signedDistance(Point2 origin, double &param) const = 0;
-    /// Converts a previously retrieved signed distance from origin to pseudo-distance.
-    virtual void distanceToPseudoDistance(SignedDistance &distance, Point2 origin, double param) const;
+    /// Converts a previously retrieved signed distance from origin to perpendicular distance.
+    virtual void distanceToPerpendicularDistance(SignedDistance &distance, Point2 origin, double param) const;
     /// Outputs a list of (at most three) intersections (their X coordinates) with an infinite horizontal scanline at y and returns how many there are.
     /// Outputs a list of (at most three) intersections (their X coordinates) with an infinite horizontal scanline at y and returns how many there are.
     virtual int scanlineIntersections(double x[3], int dy[3], double y) const = 0;
     virtual int scanlineIntersections(double x[3], int dy[3], double y) const = 0;
     /// Adjusts the bounding box to fit the edge segment.
     /// Adjusts the bounding box to fit the edge segment.

+ 51 - 51
core/edge-selectors.cpp

@@ -36,48 +36,48 @@ TrueDistanceSelector::DistanceType TrueDistanceSelector::distance() const {
     return minDistance.distance;
     return minDistance.distance;
 }
 }
 
 
-PseudoDistanceSelectorBase::EdgeCache::EdgeCache() : absDistance(0), aDomainDistance(0), bDomainDistance(0), aPseudoDistance(0), bPseudoDistance(0) { }
+PerpendicularDistanceSelectorBase::EdgeCache::EdgeCache() : absDistance(0), aDomainDistance(0), bDomainDistance(0), aPerpendicularDistance(0), bPerpendicularDistance(0) { }
 
 
-bool PseudoDistanceSelectorBase::getPseudoDistance(double &distance, const Vector2 &ep, const Vector2 &edgeDir) {
+bool PerpendicularDistanceSelectorBase::getPerpendicularDistance(double &distance, const Vector2 &ep, const Vector2 &edgeDir) {
     double ts = dotProduct(ep, edgeDir);
     double ts = dotProduct(ep, edgeDir);
     if (ts > 0) {
     if (ts > 0) {
-        double pseudoDistance = crossProduct(ep, edgeDir);
-        if (fabs(pseudoDistance) < fabs(distance)) {
-            distance = pseudoDistance;
+        double perpendicularDistance = crossProduct(ep, edgeDir);
+        if (fabs(perpendicularDistance) < fabs(distance)) {
+            distance = perpendicularDistance;
             return true;
             return true;
         }
         }
     }
     }
     return false;
     return false;
 }
 }
 
 
-PseudoDistanceSelectorBase::PseudoDistanceSelectorBase() : minNegativePseudoDistance(-fabs(minTrueDistance.distance)), minPositivePseudoDistance(fabs(minTrueDistance.distance)), nearEdge(NULL), nearEdgeParam(0) { }
+PerpendicularDistanceSelectorBase::PerpendicularDistanceSelectorBase() : minNegativePerpendicularDistance(-fabs(minTrueDistance.distance)), minPositivePerpendicularDistance(fabs(minTrueDistance.distance)), nearEdge(NULL), nearEdgeParam(0) { }
 
 
-void PseudoDistanceSelectorBase::reset(double delta) {
+void PerpendicularDistanceSelectorBase::reset(double delta) {
     minTrueDistance.distance += nonZeroSign(minTrueDistance.distance)*delta;
     minTrueDistance.distance += nonZeroSign(minTrueDistance.distance)*delta;
-    minNegativePseudoDistance = -fabs(minTrueDistance.distance);
-    minPositivePseudoDistance = fabs(minTrueDistance.distance);
+    minNegativePerpendicularDistance = -fabs(minTrueDistance.distance);
+    minPositivePerpendicularDistance = fabs(minTrueDistance.distance);
     nearEdge = NULL;
     nearEdge = NULL;
     nearEdgeParam = 0;
     nearEdgeParam = 0;
 }
 }
 
 
-bool PseudoDistanceSelectorBase::isEdgeRelevant(const EdgeCache &cache, const EdgeSegment *edge, const Point2 &p) const {
+bool PerpendicularDistanceSelectorBase::isEdgeRelevant(const EdgeCache &cache, const EdgeSegment *edge, const Point2 &p) const {
     double delta = DISTANCE_DELTA_FACTOR*(p-cache.point).length();
     double delta = DISTANCE_DELTA_FACTOR*(p-cache.point).length();
     return (
     return (
         cache.absDistance-delta <= fabs(minTrueDistance.distance) ||
         cache.absDistance-delta <= fabs(minTrueDistance.distance) ||
         fabs(cache.aDomainDistance) < delta ||
         fabs(cache.aDomainDistance) < delta ||
         fabs(cache.bDomainDistance) < delta ||
         fabs(cache.bDomainDistance) < delta ||
-        (cache.aDomainDistance > 0 && (cache.aPseudoDistance < 0 ?
-            cache.aPseudoDistance+delta >= minNegativePseudoDistance :
-            cache.aPseudoDistance-delta <= minPositivePseudoDistance
+        (cache.aDomainDistance > 0 && (cache.aPerpendicularDistance < 0 ?
+            cache.aPerpendicularDistance+delta >= minNegativePerpendicularDistance :
+            cache.aPerpendicularDistance-delta <= minPositivePerpendicularDistance
         )) ||
         )) ||
-        (cache.bDomainDistance > 0 && (cache.bPseudoDistance < 0 ?
-            cache.bPseudoDistance+delta >= minNegativePseudoDistance :
-            cache.bPseudoDistance-delta <= minPositivePseudoDistance
+        (cache.bDomainDistance > 0 && (cache.bPerpendicularDistance < 0 ?
+            cache.bPerpendicularDistance+delta >= minNegativePerpendicularDistance :
+            cache.bPerpendicularDistance-delta <= minPositivePerpendicularDistance
         ))
         ))
     );
     );
 }
 }
 
 
-void PseudoDistanceSelectorBase::addEdgeTrueDistance(const EdgeSegment *edge, const SignedDistance &distance, double param) {
+void PerpendicularDistanceSelectorBase::addEdgeTrueDistance(const EdgeSegment *edge, const SignedDistance &distance, double param) {
     if (distance < minTrueDistance) {
     if (distance < minTrueDistance) {
         minTrueDistance = distance;
         minTrueDistance = distance;
         nearEdge = edge;
         nearEdge = edge;
@@ -85,47 +85,47 @@ void PseudoDistanceSelectorBase::addEdgeTrueDistance(const EdgeSegment *edge, co
     }
     }
 }
 }
 
 
-void PseudoDistanceSelectorBase::addEdgePseudoDistance(double distance) {
-    if (distance <= 0 && distance > minNegativePseudoDistance)
-        minNegativePseudoDistance = distance;
-    if (distance >= 0 && distance < minPositivePseudoDistance)
-        minPositivePseudoDistance = distance;
+void PerpendicularDistanceSelectorBase::addEdgePerpendicularDistance(double distance) {
+    if (distance <= 0 && distance > minNegativePerpendicularDistance)
+        minNegativePerpendicularDistance = distance;
+    if (distance >= 0 && distance < minPositivePerpendicularDistance)
+        minPositivePerpendicularDistance = distance;
 }
 }
 
 
-void PseudoDistanceSelectorBase::merge(const PseudoDistanceSelectorBase &other) {
+void PerpendicularDistanceSelectorBase::merge(const PerpendicularDistanceSelectorBase &other) {
     if (other.minTrueDistance < minTrueDistance) {
     if (other.minTrueDistance < minTrueDistance) {
         minTrueDistance = other.minTrueDistance;
         minTrueDistance = other.minTrueDistance;
         nearEdge = other.nearEdge;
         nearEdge = other.nearEdge;
         nearEdgeParam = other.nearEdgeParam;
         nearEdgeParam = other.nearEdgeParam;
     }
     }
-    if (other.minNegativePseudoDistance > minNegativePseudoDistance)
-        minNegativePseudoDistance = other.minNegativePseudoDistance;
-    if (other.minPositivePseudoDistance < minPositivePseudoDistance)
-        minPositivePseudoDistance = other.minPositivePseudoDistance;
+    if (other.minNegativePerpendicularDistance > minNegativePerpendicularDistance)
+        minNegativePerpendicularDistance = other.minNegativePerpendicularDistance;
+    if (other.minPositivePerpendicularDistance < minPositivePerpendicularDistance)
+        minPositivePerpendicularDistance = other.minPositivePerpendicularDistance;
 }
 }
 
 
-double PseudoDistanceSelectorBase::computeDistance(const Point2 &p) const {
-    double minDistance = minTrueDistance.distance < 0 ? minNegativePseudoDistance : minPositivePseudoDistance;
+double PerpendicularDistanceSelectorBase::computeDistance(const Point2 &p) const {
+    double minDistance = minTrueDistance.distance < 0 ? minNegativePerpendicularDistance : minPositivePerpendicularDistance;
     if (nearEdge) {
     if (nearEdge) {
         SignedDistance distance = minTrueDistance;
         SignedDistance distance = minTrueDistance;
-        nearEdge->distanceToPseudoDistance(distance, p, nearEdgeParam);
+        nearEdge->distanceToPerpendicularDistance(distance, p, nearEdgeParam);
         if (fabs(distance.distance) < fabs(minDistance))
         if (fabs(distance.distance) < fabs(minDistance))
             minDistance = distance.distance;
             minDistance = distance.distance;
     }
     }
     return minDistance;
     return minDistance;
 }
 }
 
 
-SignedDistance PseudoDistanceSelectorBase::trueDistance() const {
+SignedDistance PerpendicularDistanceSelectorBase::trueDistance() const {
     return minTrueDistance;
     return minTrueDistance;
 }
 }
 
 
-void PseudoDistanceSelector::reset(const Point2 &p) {
+void PerpendicularDistanceSelector::reset(const Point2 &p) {
     double delta = DISTANCE_DELTA_FACTOR*(p-this->p).length();
     double delta = DISTANCE_DELTA_FACTOR*(p-this->p).length();
-    PseudoDistanceSelectorBase::reset(delta);
+    PerpendicularDistanceSelectorBase::reset(delta);
     this->p = p;
     this->p = p;
 }
 }
 
 
-void PseudoDistanceSelector::addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge) {
+void PerpendicularDistanceSelector::addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge) {
     if (isEdgeRelevant(cache, edge, p)) {
     if (isEdgeRelevant(cache, edge, p)) {
         double param;
         double param;
         SignedDistance distance = edge->signedDistance(p, param);
         SignedDistance distance = edge->signedDistance(p, param);
@@ -143,22 +143,22 @@ void PseudoDistanceSelector::addEdge(EdgeCache &cache, const EdgeSegment *prevEd
         double bdd = -dotProduct(bp, (bDir+nextDir).normalize(true));
         double bdd = -dotProduct(bp, (bDir+nextDir).normalize(true));
         if (add > 0) {
         if (add > 0) {
             double pd = distance.distance;
             double pd = distance.distance;
-            if (getPseudoDistance(pd, ap, -aDir))
-                addEdgePseudoDistance(pd = -pd);
-            cache.aPseudoDistance = pd;
+            if (getPerpendicularDistance(pd, ap, -aDir))
+                addEdgePerpendicularDistance(pd = -pd);
+            cache.aPerpendicularDistance = pd;
         }
         }
         if (bdd > 0) {
         if (bdd > 0) {
             double pd = distance.distance;
             double pd = distance.distance;
-            if (getPseudoDistance(pd, bp, bDir))
-                addEdgePseudoDistance(pd);
-            cache.bPseudoDistance = pd;
+            if (getPerpendicularDistance(pd, bp, bDir))
+                addEdgePerpendicularDistance(pd);
+            cache.bPerpendicularDistance = pd;
         }
         }
         cache.aDomainDistance = add;
         cache.aDomainDistance = add;
         cache.bDomainDistance = bdd;
         cache.bDomainDistance = bdd;
     }
     }
 }
 }
 
 
-PseudoDistanceSelector::DistanceType PseudoDistanceSelector::distance() const {
+PerpendicularDistanceSelector::DistanceType PerpendicularDistanceSelector::distance() const {
     return computeDistance(p);
     return computeDistance(p);
 }
 }
 
 
@@ -197,28 +197,28 @@ void MultiDistanceSelector::addEdge(EdgeCache &cache, const EdgeSegment *prevEdg
         double bdd = -dotProduct(bp, (bDir+nextDir).normalize(true));
         double bdd = -dotProduct(bp, (bDir+nextDir).normalize(true));
         if (add > 0) {
         if (add > 0) {
             double pd = distance.distance;
             double pd = distance.distance;
-            if (PseudoDistanceSelectorBase::getPseudoDistance(pd, ap, -aDir)) {
+            if (PerpendicularDistanceSelectorBase::getPerpendicularDistance(pd, ap, -aDir)) {
                 pd = -pd;
                 pd = -pd;
                 if (edge->color&RED)
                 if (edge->color&RED)
-                    r.addEdgePseudoDistance(pd);
+                    r.addEdgePerpendicularDistance(pd);
                 if (edge->color&GREEN)
                 if (edge->color&GREEN)
-                    g.addEdgePseudoDistance(pd);
+                    g.addEdgePerpendicularDistance(pd);
                 if (edge->color&BLUE)
                 if (edge->color&BLUE)
-                    b.addEdgePseudoDistance(pd);
+                    b.addEdgePerpendicularDistance(pd);
             }
             }
-            cache.aPseudoDistance = pd;
+            cache.aPerpendicularDistance = pd;
         }
         }
         if (bdd > 0) {
         if (bdd > 0) {
             double pd = distance.distance;
             double pd = distance.distance;
-            if (PseudoDistanceSelectorBase::getPseudoDistance(pd, bp, bDir)) {
+            if (PerpendicularDistanceSelectorBase::getPerpendicularDistance(pd, bp, bDir)) {
                 if (edge->color&RED)
                 if (edge->color&RED)
-                    r.addEdgePseudoDistance(pd);
+                    r.addEdgePerpendicularDistance(pd);
                 if (edge->color&GREEN)
                 if (edge->color&GREEN)
-                    g.addEdgePseudoDistance(pd);
+                    g.addEdgePerpendicularDistance(pd);
                 if (edge->color&BLUE)
                 if (edge->color&BLUE)
-                    b.addEdgePseudoDistance(pd);
+                    b.addEdgePerpendicularDistance(pd);
             }
             }
-            cache.bPseudoDistance = pd;
+            cache.bPerpendicularDistance = pd;
         }
         }
         cache.aDomainDistance = add;
         cache.aDomainDistance = add;
         cache.bDomainDistance = bdd;
         cache.bDomainDistance = bdd;

+ 14 - 14
core/edge-selectors.h

@@ -38,40 +38,40 @@ private:
 
 
 };
 };
 
 
-class PseudoDistanceSelectorBase {
+class PerpendicularDistanceSelectorBase {
 
 
 public:
 public:
     struct EdgeCache {
     struct EdgeCache {
         Point2 point;
         Point2 point;
         double absDistance;
         double absDistance;
         double aDomainDistance, bDomainDistance;
         double aDomainDistance, bDomainDistance;
-        double aPseudoDistance, bPseudoDistance;
+        double aPerpendicularDistance, bPerpendicularDistance;
 
 
         EdgeCache();
         EdgeCache();
     };
     };
 
 
-    static bool getPseudoDistance(double &distance, const Vector2 &ep, const Vector2 &edgeDir);
+    static bool getPerpendicularDistance(double &distance, const Vector2 &ep, const Vector2 &edgeDir);
 
 
-    PseudoDistanceSelectorBase();
+    PerpendicularDistanceSelectorBase();
     void reset(double delta);
     void reset(double delta);
     bool isEdgeRelevant(const EdgeCache &cache, const EdgeSegment *edge, const Point2 &p) const;
     bool isEdgeRelevant(const EdgeCache &cache, const EdgeSegment *edge, const Point2 &p) const;
     void addEdgeTrueDistance(const EdgeSegment *edge, const SignedDistance &distance, double param);
     void addEdgeTrueDistance(const EdgeSegment *edge, const SignedDistance &distance, double param);
-    void addEdgePseudoDistance(double distance);
-    void merge(const PseudoDistanceSelectorBase &other);
+    void addEdgePerpendicularDistance(double distance);
+    void merge(const PerpendicularDistanceSelectorBase &other);
     double computeDistance(const Point2 &p) const;
     double computeDistance(const Point2 &p) const;
     SignedDistance trueDistance() const;
     SignedDistance trueDistance() const;
 
 
 private:
 private:
     SignedDistance minTrueDistance;
     SignedDistance minTrueDistance;
-    double minNegativePseudoDistance;
-    double minPositivePseudoDistance;
+    double minNegativePerpendicularDistance;
+    double minPositivePerpendicularDistance;
     const EdgeSegment *nearEdge;
     const EdgeSegment *nearEdge;
     double nearEdgeParam;
     double nearEdgeParam;
 
 
 };
 };
 
 
-/// Selects the nearest edge by its pseudo-distance.
-class PseudoDistanceSelector : public PseudoDistanceSelectorBase {
+/// Selects the nearest edge by its perpendicular distance.
+class PerpendicularDistanceSelector : public PerpendicularDistanceSelectorBase {
 
 
 public:
 public:
     typedef double DistanceType;
     typedef double DistanceType;
@@ -85,12 +85,12 @@ private:
 
 
 };
 };
 
 
-/// Selects the nearest edge for each of the three channels by its pseudo-distance.
+/// Selects the nearest edge for each of the three channels by its perpendicular distance.
 class MultiDistanceSelector {
 class MultiDistanceSelector {
 
 
 public:
 public:
     typedef MultiDistance DistanceType;
     typedef MultiDistance DistanceType;
-    typedef PseudoDistanceSelectorBase::EdgeCache EdgeCache;
+    typedef PerpendicularDistanceSelectorBase::EdgeCache EdgeCache;
 
 
     void reset(const Point2 &p);
     void reset(const Point2 &p);
     void addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge);
     void addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge);
@@ -100,11 +100,11 @@ public:
 
 
 private:
 private:
     Point2 p;
     Point2 p;
-    PseudoDistanceSelectorBase r, g, b;
+    PerpendicularDistanceSelectorBase r, g, b;
 
 
 };
 };
 
 
-/// Selects the nearest edge for each of the three color channels by its pseudo-distance and by true distance for the alpha channel.
+/// Selects the nearest edge for each of the three color channels by its perpendicular distance and by true distance for the alpha channel.
 class MultiAndTrueDistanceSelector : public MultiDistanceSelector {
 class MultiAndTrueDistanceSelector : public MultiDistanceSelector {
 
 
 public:
 public:

+ 24 - 12
core/msdfgen.cpp

@@ -81,11 +81,11 @@ void generateSDF(const BitmapRef<float, 1> &output, const Shape &shape, const Pr
         generateDistanceField<SimpleContourCombiner<TrueDistanceSelector> >(output, shape, projection, range);
         generateDistanceField<SimpleContourCombiner<TrueDistanceSelector> >(output, shape, projection, range);
 }
 }
 
 
-void generatePseudoSDF(const BitmapRef<float, 1> &output, const Shape &shape, const Projection &projection, double range, const GeneratorConfig &config) {
+void generatePSDF(const BitmapRef<float, 1> &output, const Shape &shape, const Projection &projection, double range, const GeneratorConfig &config) {
     if (config.overlapSupport)
     if (config.overlapSupport)
-        generateDistanceField<OverlappingContourCombiner<PseudoDistanceSelector> >(output, shape, projection, range);
+        generateDistanceField<OverlappingContourCombiner<PerpendicularDistanceSelector> >(output, shape, projection, range);
     else
     else
-        generateDistanceField<SimpleContourCombiner<PseudoDistanceSelector> >(output, shape, projection, range);
+        generateDistanceField<SimpleContourCombiner<PerpendicularDistanceSelector> >(output, shape, projection, range);
 }
 }
 
 
 void generateMSDF(const BitmapRef<float, 3> &output, const Shape &shape, const Projection &projection, double range, const MSDFGeneratorConfig &config) {
 void generateMSDF(const BitmapRef<float, 3> &output, const Shape &shape, const Projection &projection, double range, const MSDFGeneratorConfig &config) {
@@ -106,12 +106,20 @@ void generateMTSDF(const BitmapRef<float, 4> &output, const Shape &shape, const
 
 
 // Legacy API
 // Legacy API
 
 
+void generatePseudoSDF(const BitmapRef<float, 1> &output, const Shape &shape, const Projection &projection, double range, const GeneratorConfig &config) {
+    generatePSDF(output, shape, projection, range, config);
+}
+
 void generateSDF(const BitmapRef<float, 1> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport) {
 void generateSDF(const BitmapRef<float, 1> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport) {
     generateSDF(output, shape, Projection(scale, translate), range, GeneratorConfig(overlapSupport));
     generateSDF(output, shape, Projection(scale, translate), range, GeneratorConfig(overlapSupport));
 }
 }
 
 
+void generatePSDF(const BitmapRef<float, 1> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport) {
+    generatePSDF(output, shape, Projection(scale, translate), range, GeneratorConfig(overlapSupport));
+}
+
 void generatePseudoSDF(const BitmapRef<float, 1> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport) {
 void generatePseudoSDF(const BitmapRef<float, 1> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport) {
-    generatePseudoSDF(output, shape, Projection(scale, translate), range, GeneratorConfig(overlapSupport));
+    generatePSDF(output, shape, Projection(scale, translate), range, GeneratorConfig(overlapSupport));
 }
 }
 
 
 void generateMSDF(const BitmapRef<float, 3> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, const ErrorCorrectionConfig &errorCorrectionConfig, bool overlapSupport) {
 void generateMSDF(const BitmapRef<float, 3> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, const ErrorCorrectionConfig &errorCorrectionConfig, bool overlapSupport) {
@@ -145,7 +153,7 @@ void generateSDF_legacy(const BitmapRef<float, 1> &output, const Shape &shape, d
     }
     }
 }
 }
 
 
-void generatePseudoSDF_legacy(const BitmapRef<float, 1> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate) {
+void generatePSDF_legacy(const BitmapRef<float, 1> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate) {
 #ifdef MSDFGEN_USE_OPENMP
 #ifdef MSDFGEN_USE_OPENMP
     #pragma omp parallel for
     #pragma omp parallel for
 #endif
 #endif
@@ -167,12 +175,16 @@ void generatePseudoSDF_legacy(const BitmapRef<float, 1> &output, const Shape &sh
                     }
                     }
                 }
                 }
             if (nearEdge)
             if (nearEdge)
-                (*nearEdge)->distanceToPseudoDistance(minDistance, p, nearParam);
+                (*nearEdge)->distanceToPerpendicularDistance(minDistance, p, nearParam);
             *output(x, row) = float(minDistance.distance/range+.5);
             *output(x, row) = float(minDistance.distance/range+.5);
         }
         }
     }
     }
 }
 }
 
 
+void generatePseudoSDF_legacy(const BitmapRef<float, 1> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate) {
+    generatePSDF_legacy(output, shape, range, scale, translate);
+}
+
 void generateMSDF_legacy(const BitmapRef<float, 3> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, ErrorCorrectionConfig errorCorrectionConfig) {
 void generateMSDF_legacy(const BitmapRef<float, 3> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, ErrorCorrectionConfig errorCorrectionConfig) {
 #ifdef MSDFGEN_USE_OPENMP
 #ifdef MSDFGEN_USE_OPENMP
     #pragma omp parallel for
     #pragma omp parallel for
@@ -212,11 +224,11 @@ void generateMSDF_legacy(const BitmapRef<float, 3> &output, const Shape &shape,
                 }
                 }
 
 
             if (r.nearEdge)
             if (r.nearEdge)
-                (*r.nearEdge)->distanceToPseudoDistance(r.minDistance, p, r.nearParam);
+                (*r.nearEdge)->distanceToPerpendicularDistance(r.minDistance, p, r.nearParam);
             if (g.nearEdge)
             if (g.nearEdge)
-                (*g.nearEdge)->distanceToPseudoDistance(g.minDistance, p, g.nearParam);
+                (*g.nearEdge)->distanceToPerpendicularDistance(g.minDistance, p, g.nearParam);
             if (b.nearEdge)
             if (b.nearEdge)
-                (*b.nearEdge)->distanceToPseudoDistance(b.minDistance, p, b.nearParam);
+                (*b.nearEdge)->distanceToPerpendicularDistance(b.minDistance, p, b.nearParam);
             output(x, row)[0] = float(r.minDistance.distance/range+.5);
             output(x, row)[0] = float(r.minDistance.distance/range+.5);
             output(x, row)[1] = float(g.minDistance.distance/range+.5);
             output(x, row)[1] = float(g.minDistance.distance/range+.5);
             output(x, row)[2] = float(b.minDistance.distance/range+.5);
             output(x, row)[2] = float(b.minDistance.distance/range+.5);
@@ -269,11 +281,11 @@ void generateMTSDF_legacy(const BitmapRef<float, 4> &output, const Shape &shape,
                 }
                 }
 
 
             if (r.nearEdge)
             if (r.nearEdge)
-                (*r.nearEdge)->distanceToPseudoDistance(r.minDistance, p, r.nearParam);
+                (*r.nearEdge)->distanceToPerpendicularDistance(r.minDistance, p, r.nearParam);
             if (g.nearEdge)
             if (g.nearEdge)
-                (*g.nearEdge)->distanceToPseudoDistance(g.minDistance, p, g.nearParam);
+                (*g.nearEdge)->distanceToPerpendicularDistance(g.minDistance, p, g.nearParam);
             if (b.nearEdge)
             if (b.nearEdge)
-                (*b.nearEdge)->distanceToPseudoDistance(b.minDistance, p, b.nearParam);
+                (*b.nearEdge)->distanceToPerpendicularDistance(b.minDistance, p, b.nearParam);
             output(x, row)[0] = float(r.minDistance.distance/range+.5);
             output(x, row)[0] = float(r.minDistance.distance/range+.5);
             output(x, row)[1] = float(g.minDistance.distance/range+.5);
             output(x, row)[1] = float(g.minDistance.distance/range+.5);
             output(x, row)[2] = float(b.minDistance.distance/range+.5);
             output(x, row)[2] = float(b.minDistance.distance/range+.5);

+ 17 - 14
main.cpp

@@ -358,7 +358,7 @@ static const char *const helpText =
     "\n"
     "\n"
     "MODES\n"
     "MODES\n"
     "  sdf - Generate conventional monochrome (true) signed distance field.\n"
     "  sdf - Generate conventional monochrome (true) signed distance field.\n"
-    "  psdf - Generate monochrome signed pseudo-distance field.\n"
+    "  psdf - Generate monochrome signed perpendicular distance field.\n"
     "  msdf - Generate multi-channel signed distance field. This is used by default if no mode is specified.\n"
     "  msdf - Generate multi-channel signed distance field. This is used by default if no mode is specified.\n"
     "  mtsdf - Generate combined multi-channel and true signed distance field in the alpha channel.\n"
     "  mtsdf - Generate combined multi-channel and true signed distance field in the alpha channel.\n"
     "  metrics - Report shape metrics only.\n"
     "  metrics - Report shape metrics only.\n"
@@ -513,7 +513,7 @@ int main(int argc, const char *const *argv) {
     } inputType = NONE;
     } inputType = NONE;
     enum {
     enum {
         SINGLE,
         SINGLE,
-        PSEUDO,
+        PERPENDICULAR,
         MULTI,
         MULTI,
         MULTI_AND_TRUE,
         MULTI_AND_TRUE,
         METRICS
         METRICS
@@ -573,7 +573,7 @@ int main(int argc, const char *const *argv) {
         GUESS
         GUESS
     } orientation = KEEP;
     } orientation = KEEP;
     unsigned long long coloringSeed = 0;
     unsigned long long coloringSeed = 0;
-    void (*edgeColoring)(Shape &, double, unsigned long long) = edgeColoringSimple;
+    void (*edgeColoring)(Shape &, double, unsigned long long) = &edgeColoringSimple;
     bool explicitErrorCorrectionMode = false;
     bool explicitErrorCorrectionMode = false;
 
 
     int argPos = 1;
     int argPos = 1;
@@ -589,7 +589,7 @@ int main(int argc, const char *const *argv) {
             ++arg;
             ++arg;
 
 
         ARG_MODE("sdf", SINGLE)
         ARG_MODE("sdf", SINGLE)
-        ARG_MODE("psdf", PSEUDO)
+        ARG_MODE("psdf", PERPENDICULAR)
         ARG_MODE("msdf", MULTI)
         ARG_MODE("msdf", MULTI)
         ARG_MODE("mtsdf", MULTI_AND_TRUE)
         ARG_MODE("mtsdf", MULTI_AND_TRUE)
         ARG_MODE("metrics", METRICS)
         ARG_MODE("metrics", METRICS)
@@ -856,9 +856,12 @@ int main(int argc, const char *const *argv) {
             continue;
             continue;
         }
         }
         ARG_CASE("-coloringstrategy", 1) {
         ARG_CASE("-coloringstrategy", 1) {
-            if (!strcmp(argv[argPos+1], "simple")) edgeColoring = edgeColoringSimple;
-            else if (!strcmp(argv[argPos+1], "inktrap")) edgeColoring = edgeColoringInkTrap;
-            else if (!strcmp(argv[argPos+1], "distance")) edgeColoring = edgeColoringByDistance;
+            if (!strcmp(argv[argPos+1], "simple"))
+                edgeColoring = &edgeColoringSimple;
+            else if (!strcmp(argv[argPos+1], "inktrap"))
+                edgeColoring = &edgeColoringInkTrap;
+            else if (!strcmp(argv[argPos+1], "distance"))
+                edgeColoring = &edgeColoringByDistance;
             else
             else
                 fputs("Unknown coloring strategy specified.\n", stderr);
                 fputs("Unknown coloring strategy specified.\n", stderr);
             argPos += 2;
             argPos += 2;
@@ -1164,12 +1167,12 @@ int main(int argc, const char *const *argv) {
                 generateSDF(sdf, shape, projection, range, generatorConfig);
                 generateSDF(sdf, shape, projection, range, generatorConfig);
             break;
             break;
         }
         }
-        case PSEUDO: {
+        case PERPENDICULAR: {
             sdf = Bitmap<float, 1>(width, height);
             sdf = Bitmap<float, 1>(width, height);
             if (legacyMode)
             if (legacyMode)
-                generatePseudoSDF_legacy(sdf, shape, range, scale, translate);
+                generatePSDF_legacy(sdf, shape, range, scale, translate);
             else
             else
-                generatePseudoSDF(sdf, shape, projection, range, generatorConfig);
+                generatePSDF(sdf, shape, projection, range, generatorConfig);
             break;
             break;
         }
         }
         case MULTI: {
         case MULTI: {
@@ -1208,7 +1211,7 @@ int main(int argc, const char *const *argv) {
     if (orientation == REVERSE) {
     if (orientation == REVERSE) {
         switch (mode) {
         switch (mode) {
             case SINGLE:
             case SINGLE:
-            case PSEUDO:
+            case PERPENDICULAR:
                 invertColor<1>(sdf);
                 invertColor<1>(sdf);
                 break;
                 break;
             case MULTI:
             case MULTI:
@@ -1223,7 +1226,7 @@ int main(int argc, const char *const *argv) {
     if (scanlinePass) {
     if (scanlinePass) {
         switch (mode) {
         switch (mode) {
             case SINGLE:
             case SINGLE:
-            case PSEUDO:
+            case PERPENDICULAR:
                 distanceSignCorrection(sdf, shape, projection, fillRule);
                 distanceSignCorrection(sdf, shape, projection, fillRule);
                 break;
                 break;
             case MULTI:
             case MULTI:
@@ -1241,7 +1244,7 @@ int main(int argc, const char *const *argv) {
         float *pixel = NULL, *pixelsEnd = NULL;
         float *pixel = NULL, *pixelsEnd = NULL;
         switch (mode) {
         switch (mode) {
             case SINGLE:
             case SINGLE:
-            case PSEUDO:
+            case PERPENDICULAR:
                 pixel = (float *) sdf;
                 pixel = (float *) sdf;
                 pixelsEnd = pixel+1*sdf.width()*sdf.height();
                 pixelsEnd = pixel+1*sdf.width()*sdf.height();
                 break;
                 break;
@@ -1271,7 +1274,7 @@ int main(int argc, const char *const *argv) {
     const char *error = NULL;
     const char *error = NULL;
     switch (mode) {
     switch (mode) {
         case SINGLE:
         case SINGLE:
-        case PSEUDO:
+        case PERPENDICULAR:
             if ((error = writeOutput<1>(sdf, output, format))) {
             if ((error = writeOutput<1>(sdf, output, format))) {
                 fprintf(stderr, "%s\n", error);
                 fprintf(stderr, "%s\n", error);
                 return 1;
                 return 1;

+ 6 - 2
msdfgen.h

@@ -40,8 +40,8 @@ namespace msdfgen {
 /// Generates a conventional single-channel signed distance field.
 /// Generates a conventional single-channel signed distance field.
 void generateSDF(const BitmapRef<float, 1> &output, const Shape &shape, const Projection &projection, double range, const GeneratorConfig &config = GeneratorConfig());
 void generateSDF(const BitmapRef<float, 1> &output, const Shape &shape, const Projection &projection, double range, const GeneratorConfig &config = GeneratorConfig());
 
 
-/// Generates a single-channel signed pseudo-distance field.
-void generatePseudoSDF(const BitmapRef<float, 1> &output, const Shape &shape, const Projection &projection, double range, const GeneratorConfig &config = GeneratorConfig());
+/// Generates a single-channel signed perpendicular distance field.
+void generatePSDF(const BitmapRef<float, 1> &output, const Shape &shape, const Projection &projection, double range, const GeneratorConfig &config = GeneratorConfig());
 
 
 /// Generates a multi-channel signed distance field. Edge colors must be assigned first! (See edgeColoringSimple)
 /// Generates a multi-channel signed distance field. Edge colors must be assigned first! (See edgeColoringSimple)
 void generateMSDF(const BitmapRef<float, 3> &output, const Shape &shape, const Projection &projection, double range, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
 void generateMSDF(const BitmapRef<float, 3> &output, const Shape &shape, const Projection &projection, double range, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
@@ -50,13 +50,17 @@ void generateMSDF(const BitmapRef<float, 3> &output, const Shape &shape, const P
 void generateMTSDF(const BitmapRef<float, 4> &output, const Shape &shape, const Projection &projection, double range, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
 void generateMTSDF(const BitmapRef<float, 4> &output, const Shape &shape, const Projection &projection, double range, const MSDFGeneratorConfig &config = MSDFGeneratorConfig());
 
 
 // Old version of the function API's kept for backwards compatibility
 // Old version of the function API's kept for backwards compatibility
+void generatePseudoSDF(const BitmapRef<float, 1> &output, const Shape &shape, const Projection &projection, double range, const GeneratorConfig &config = GeneratorConfig());
+
 void generateSDF(const BitmapRef<float, 1> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport = true);
 void generateSDF(const BitmapRef<float, 1> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport = true);
+void generatePSDF(const BitmapRef<float, 1> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport = true);
 void generatePseudoSDF(const BitmapRef<float, 1> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport = true);
 void generatePseudoSDF(const BitmapRef<float, 1> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport = true);
 void generateMSDF(const BitmapRef<float, 3> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, const ErrorCorrectionConfig &errorCorrectionConfig = ErrorCorrectionConfig(), bool overlapSupport = true);
 void generateMSDF(const BitmapRef<float, 3> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, const ErrorCorrectionConfig &errorCorrectionConfig = ErrorCorrectionConfig(), bool overlapSupport = true);
 void generateMTSDF(const BitmapRef<float, 4> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, const ErrorCorrectionConfig &errorCorrectionConfig = ErrorCorrectionConfig(), bool overlapSupport = true);
 void generateMTSDF(const BitmapRef<float, 4> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, const ErrorCorrectionConfig &errorCorrectionConfig = ErrorCorrectionConfig(), bool overlapSupport = true);
 
 
 // Original simpler versions of the previous functions, which work well under normal circumstances, but cannot deal with overlapping contours.
 // Original simpler versions of the previous functions, which work well under normal circumstances, but cannot deal with overlapping contours.
 void generateSDF_legacy(const BitmapRef<float, 1> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate);
 void generateSDF_legacy(const BitmapRef<float, 1> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate);
+void generatePSDF_legacy(const BitmapRef<float, 1> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate);
 void generatePseudoSDF_legacy(const BitmapRef<float, 1> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate);
 void generatePseudoSDF_legacy(const BitmapRef<float, 1> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate);
 void generateMSDF_legacy(const BitmapRef<float, 3> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, ErrorCorrectionConfig errorCorrectionConfig = ErrorCorrectionConfig());
 void generateMSDF_legacy(const BitmapRef<float, 3> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, ErrorCorrectionConfig errorCorrectionConfig = ErrorCorrectionConfig());
 void generateMTSDF_legacy(const BitmapRef<float, 4> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, ErrorCorrectionConfig errorCorrectionConfig = ErrorCorrectionConfig());
 void generateMTSDF_legacy(const BitmapRef<float, 4> &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, ErrorCorrectionConfig errorCorrectionConfig = ErrorCorrectionConfig());