From 64c3e24829b0ebaa4547060f9c2735990a8d0d8b Mon Sep 17 00:00:00 2001 From: Chlumsky Date: Sun, 10 Mar 2024 10:30:59 +0100 Subject: [PATCH] Renamed pseudo-distance to perpendicular distance --- README.md | 11 ++-- core/MSDFErrorCorrection.cpp | 2 +- core/contour-combiners.cpp | 4 +- core/edge-segments.cpp | 14 ++--- core/edge-segments.h | 4 +- core/edge-selectors.cpp | 102 +++++++++++++++++------------------ core/edge-selectors.h | 28 +++++----- core/msdfgen.cpp | 36 ++++++++----- main.cpp | 31 ++++++----- msdfgen.h | 8 ++- 10 files changed, 129 insertions(+), 111 deletions(-) diff --git a/README.md b/README.md index 03a4fed..470b070 100644 --- a/README.md +++ b/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. 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) -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 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: - **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. - **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`, 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. - 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`. - 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. diff --git a/core/MSDFErrorCorrection.cpp b/core/MSDFErrorCorrection.cpp index 9a5cefe..94b6845 100644 --- a/core/MSDFErrorCorrection.cpp +++ b/core/MSDFErrorCorrection.cpp @@ -94,7 +94,7 @@ public: return ArtifactClassifier(this, direction, span); } private: - ShapeDistanceFinder > distanceFinder; + ShapeDistanceFinder > distanceFinder; BitmapConstRef sdf; double invRange; Vector2 texelSize; diff --git a/core/contour-combiners.cpp b/core/contour-combiners.cpp index d97959c..e15a43f 100644 --- a/core/contour-combiners.cpp +++ b/core/contour-combiners.cpp @@ -50,7 +50,7 @@ typename SimpleContourCombiner::DistanceType SimpleContourCombiner } template class SimpleContourCombiner; -template class SimpleContourCombiner; +template class SimpleContourCombiner; template class SimpleContourCombiner; template class SimpleContourCombiner; @@ -134,7 +134,7 @@ typename OverlappingContourCombiner::DistanceType OverlappingConto } template class OverlappingContourCombiner; -template class OverlappingContourCombiner; +template class OverlappingContourCombiner; template class OverlappingContourCombiner; template class OverlappingContourCombiner; diff --git a/core/edge-segments.cpp b/core/edge-segments.cpp index aad32e2..74a2788 100644 --- a/core/edge-segments.cpp +++ b/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); } -void EdgeSegment::distanceToPseudoDistance(SignedDistance &distance, Point2 origin, double param) const { +void EdgeSegment::distanceToPerpendicularDistance(SignedDistance &distance, Point2 origin, double param) const { if (param < 0) { Vector2 dir = direction(0).normalize(); Vector2 aq = origin-point(0); double ts = dotProduct(aq, dir); 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; } } @@ -42,9 +42,9 @@ void EdgeSegment::distanceToPseudoDistance(SignedDistance &distance, Point2 orig Vector2 bq = origin-point(1); double ts = dotProduct(bq, dir); 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; } } diff --git a/core/edge-segments.h b/core/edge-segments.h index e34982f..2bd8967 100644 --- a/core/edge-segments.h +++ b/core/edge-segments.h @@ -37,8 +37,8 @@ public: virtual Vector2 directionChange(double param) const = 0; /// Returns the minimum signed distance between origin and the edge. virtual SignedDistance signedDistance(Point2 origin, double ¶m) 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. virtual int scanlineIntersections(double x[3], int dy[3], double y) const = 0; /// Adjusts the bounding box to fit the edge segment. diff --git a/core/edge-selectors.cpp b/core/edge-selectors.cpp index aee7884..e4e7fbe 100644 --- a/core/edge-selectors.cpp +++ b/core/edge-selectors.cpp @@ -36,48 +36,48 @@ TrueDistanceSelector::DistanceType TrueDistanceSelector::distance() const { 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); 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 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; - minNegativePseudoDistance = -fabs(minTrueDistance.distance); - minPositivePseudoDistance = fabs(minTrueDistance.distance); + minNegativePerpendicularDistance = -fabs(minTrueDistance.distance); + minPositivePerpendicularDistance = fabs(minTrueDistance.distance); nearEdge = NULL; 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(); return ( cache.absDistance-delta <= fabs(minTrueDistance.distance) || fabs(cache.aDomainDistance) < 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) { minTrueDistance = distance; 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) { minTrueDistance = other.minTrueDistance; nearEdge = other.nearEdge; 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) { SignedDistance distance = minTrueDistance; - nearEdge->distanceToPseudoDistance(distance, p, nearEdgeParam); + nearEdge->distanceToPerpendicularDistance(distance, p, nearEdgeParam); if (fabs(distance.distance) < fabs(minDistance)) minDistance = distance.distance; } return minDistance; } -SignedDistance PseudoDistanceSelectorBase::trueDistance() const { +SignedDistance PerpendicularDistanceSelectorBase::trueDistance() const { return minTrueDistance; } -void PseudoDistanceSelector::reset(const Point2 &p) { +void PerpendicularDistanceSelector::reset(const Point2 &p) { double delta = DISTANCE_DELTA_FACTOR*(p-this->p).length(); - PseudoDistanceSelectorBase::reset(delta); + PerpendicularDistanceSelectorBase::reset(delta); 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)) { double 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)); if (add > 0) { 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) { 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.bDomainDistance = bdd; } } -PseudoDistanceSelector::DistanceType PseudoDistanceSelector::distance() const { +PerpendicularDistanceSelector::DistanceType PerpendicularDistanceSelector::distance() const { return computeDistance(p); } @@ -197,28 +197,28 @@ void MultiDistanceSelector::addEdge(EdgeCache &cache, const EdgeSegment *prevEdg double bdd = -dotProduct(bp, (bDir+nextDir).normalize(true)); if (add > 0) { double pd = distance.distance; - if (PseudoDistanceSelectorBase::getPseudoDistance(pd, ap, -aDir)) { + if (PerpendicularDistanceSelectorBase::getPerpendicularDistance(pd, ap, -aDir)) { pd = -pd; if (edge->color&RED) - r.addEdgePseudoDistance(pd); + r.addEdgePerpendicularDistance(pd); if (edge->color&GREEN) - g.addEdgePseudoDistance(pd); + g.addEdgePerpendicularDistance(pd); if (edge->color&BLUE) - b.addEdgePseudoDistance(pd); + b.addEdgePerpendicularDistance(pd); } - cache.aPseudoDistance = pd; + cache.aPerpendicularDistance = pd; } if (bdd > 0) { double pd = distance.distance; - if (PseudoDistanceSelectorBase::getPseudoDistance(pd, bp, bDir)) { + if (PerpendicularDistanceSelectorBase::getPerpendicularDistance(pd, bp, bDir)) { if (edge->color&RED) - r.addEdgePseudoDistance(pd); + r.addEdgePerpendicularDistance(pd); if (edge->color&GREEN) - g.addEdgePseudoDistance(pd); + g.addEdgePerpendicularDistance(pd); if (edge->color&BLUE) - b.addEdgePseudoDistance(pd); + b.addEdgePerpendicularDistance(pd); } - cache.bPseudoDistance = pd; + cache.bPerpendicularDistance = pd; } cache.aDomainDistance = add; cache.bDomainDistance = bdd; diff --git a/core/edge-selectors.h b/core/edge-selectors.h index 6b8e2d9..5933714 100644 --- a/core/edge-selectors.h +++ b/core/edge-selectors.h @@ -38,40 +38,40 @@ private: }; -class PseudoDistanceSelectorBase { +class PerpendicularDistanceSelectorBase { public: struct EdgeCache { Point2 point; double absDistance; double aDomainDistance, bDomainDistance; - double aPseudoDistance, bPseudoDistance; + double aPerpendicularDistance, bPerpendicularDistance; 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); bool isEdgeRelevant(const EdgeCache &cache, const EdgeSegment *edge, const Point2 &p) const; 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; SignedDistance trueDistance() const; private: SignedDistance minTrueDistance; - double minNegativePseudoDistance; - double minPositivePseudoDistance; + double minNegativePerpendicularDistance; + double minPositivePerpendicularDistance; const EdgeSegment *nearEdge; 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: 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 { public: typedef MultiDistance DistanceType; - typedef PseudoDistanceSelectorBase::EdgeCache EdgeCache; + typedef PerpendicularDistanceSelectorBase::EdgeCache EdgeCache; void reset(const Point2 &p); void addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge); @@ -100,11 +100,11 @@ public: private: 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 { public: diff --git a/core/msdfgen.cpp b/core/msdfgen.cpp index 0289295..9d0117d 100644 --- a/core/msdfgen.cpp +++ b/core/msdfgen.cpp @@ -81,11 +81,11 @@ void generateSDF(const BitmapRef &output, const Shape &shape, const Pr generateDistanceField >(output, shape, projection, range); } -void generatePseudoSDF(const BitmapRef &output, const Shape &shape, const Projection &projection, double range, const GeneratorConfig &config) { +void generatePSDF(const BitmapRef &output, const Shape &shape, const Projection &projection, double range, const GeneratorConfig &config) { if (config.overlapSupport) - generateDistanceField >(output, shape, projection, range); + generateDistanceField >(output, shape, projection, range); else - generateDistanceField >(output, shape, projection, range); + generateDistanceField >(output, shape, projection, range); } void generateMSDF(const BitmapRef &output, const Shape &shape, const Projection &projection, double range, const MSDFGeneratorConfig &config) { @@ -106,12 +106,20 @@ void generateMTSDF(const BitmapRef &output, const Shape &shape, const // Legacy API +void generatePseudoSDF(const BitmapRef &output, const Shape &shape, const Projection &projection, double range, const GeneratorConfig &config) { + generatePSDF(output, shape, projection, range, config); +} + void generateSDF(const BitmapRef &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport) { generateSDF(output, shape, Projection(scale, translate), range, GeneratorConfig(overlapSupport)); } +void generatePSDF(const BitmapRef &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 &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 &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 &output, const Shape &shape, d } } -void generatePseudoSDF_legacy(const BitmapRef &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate) { +void generatePSDF_legacy(const BitmapRef &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate) { #ifdef MSDFGEN_USE_OPENMP #pragma omp parallel for #endif @@ -167,12 +175,16 @@ void generatePseudoSDF_legacy(const BitmapRef &output, const Shape &sh } } if (nearEdge) - (*nearEdge)->distanceToPseudoDistance(minDistance, p, nearParam); + (*nearEdge)->distanceToPerpendicularDistance(minDistance, p, nearParam); *output(x, row) = float(minDistance.distance/range+.5); } } } +void generatePseudoSDF_legacy(const BitmapRef &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate) { + generatePSDF_legacy(output, shape, range, scale, translate); +} + void generateMSDF_legacy(const BitmapRef &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, ErrorCorrectionConfig errorCorrectionConfig) { #ifdef MSDFGEN_USE_OPENMP #pragma omp parallel for @@ -212,11 +224,11 @@ void generateMSDF_legacy(const BitmapRef &output, const Shape &shape, } if (r.nearEdge) - (*r.nearEdge)->distanceToPseudoDistance(r.minDistance, p, r.nearParam); + (*r.nearEdge)->distanceToPerpendicularDistance(r.minDistance, p, r.nearParam); if (g.nearEdge) - (*g.nearEdge)->distanceToPseudoDistance(g.minDistance, p, g.nearParam); + (*g.nearEdge)->distanceToPerpendicularDistance(g.minDistance, p, g.nearParam); 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)[1] = float(g.minDistance.distance/range+.5); output(x, row)[2] = float(b.minDistance.distance/range+.5); @@ -269,11 +281,11 @@ void generateMTSDF_legacy(const BitmapRef &output, const Shape &shape, } if (r.nearEdge) - (*r.nearEdge)->distanceToPseudoDistance(r.minDistance, p, r.nearParam); + (*r.nearEdge)->distanceToPerpendicularDistance(r.minDistance, p, r.nearParam); if (g.nearEdge) - (*g.nearEdge)->distanceToPseudoDistance(g.minDistance, p, g.nearParam); + (*g.nearEdge)->distanceToPerpendicularDistance(g.minDistance, p, g.nearParam); 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)[1] = float(g.minDistance.distance/range+.5); output(x, row)[2] = float(b.minDistance.distance/range+.5); diff --git a/main.cpp b/main.cpp index 5645a47..3569ff9 100644 --- a/main.cpp +++ b/main.cpp @@ -358,7 +358,7 @@ static const char *const helpText = "\n" "MODES\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" " mtsdf - Generate combined multi-channel and true signed distance field in the alpha channel.\n" " metrics - Report shape metrics only.\n" @@ -513,7 +513,7 @@ int main(int argc, const char *const *argv) { } inputType = NONE; enum { SINGLE, - PSEUDO, + PERPENDICULAR, MULTI, MULTI_AND_TRUE, METRICS @@ -573,7 +573,7 @@ int main(int argc, const char *const *argv) { GUESS } orientation = KEEP; unsigned long long coloringSeed = 0; - void (*edgeColoring)(Shape &, double, unsigned long long) = edgeColoringSimple; + void (*edgeColoring)(Shape &, double, unsigned long long) = &edgeColoringSimple; bool explicitErrorCorrectionMode = false; int argPos = 1; @@ -589,7 +589,7 @@ int main(int argc, const char *const *argv) { ++arg; ARG_MODE("sdf", SINGLE) - ARG_MODE("psdf", PSEUDO) + ARG_MODE("psdf", PERPENDICULAR) ARG_MODE("msdf", MULTI) ARG_MODE("mtsdf", MULTI_AND_TRUE) ARG_MODE("metrics", METRICS) @@ -856,9 +856,12 @@ int main(int argc, const char *const *argv) { continue; } 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 fputs("Unknown coloring strategy specified.\n", stderr); argPos += 2; @@ -1164,12 +1167,12 @@ int main(int argc, const char *const *argv) { generateSDF(sdf, shape, projection, range, generatorConfig); break; } - case PSEUDO: { + case PERPENDICULAR: { sdf = Bitmap(width, height); if (legacyMode) - generatePseudoSDF_legacy(sdf, shape, range, scale, translate); + generatePSDF_legacy(sdf, shape, range, scale, translate); else - generatePseudoSDF(sdf, shape, projection, range, generatorConfig); + generatePSDF(sdf, shape, projection, range, generatorConfig); break; } case MULTI: { @@ -1208,7 +1211,7 @@ int main(int argc, const char *const *argv) { if (orientation == REVERSE) { switch (mode) { case SINGLE: - case PSEUDO: + case PERPENDICULAR: invertColor<1>(sdf); break; case MULTI: @@ -1223,7 +1226,7 @@ int main(int argc, const char *const *argv) { if (scanlinePass) { switch (mode) { case SINGLE: - case PSEUDO: + case PERPENDICULAR: distanceSignCorrection(sdf, shape, projection, fillRule); break; case MULTI: @@ -1241,7 +1244,7 @@ int main(int argc, const char *const *argv) { float *pixel = NULL, *pixelsEnd = NULL; switch (mode) { case SINGLE: - case PSEUDO: + case PERPENDICULAR: pixel = (float *) sdf; pixelsEnd = pixel+1*sdf.width()*sdf.height(); break; @@ -1271,7 +1274,7 @@ int main(int argc, const char *const *argv) { const char *error = NULL; switch (mode) { case SINGLE: - case PSEUDO: + case PERPENDICULAR: if ((error = writeOutput<1>(sdf, output, format))) { fprintf(stderr, "%s\n", error); return 1; diff --git a/msdfgen.h b/msdfgen.h index 8a66039..18e8f83 100644 --- a/msdfgen.h +++ b/msdfgen.h @@ -40,8 +40,8 @@ namespace msdfgen { /// Generates a conventional single-channel signed distance field. void generateSDF(const BitmapRef &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 &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 &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) void generateMSDF(const BitmapRef &output, const Shape &shape, const Projection &projection, double range, const MSDFGeneratorConfig &config = MSDFGeneratorConfig()); @@ -50,13 +50,17 @@ void generateMSDF(const BitmapRef &output, const Shape &shape, const P void generateMTSDF(const BitmapRef &output, const Shape &shape, const Projection &projection, double range, const MSDFGeneratorConfig &config = MSDFGeneratorConfig()); // Old version of the function API's kept for backwards compatibility +void generatePseudoSDF(const BitmapRef &output, const Shape &shape, const Projection &projection, double range, const GeneratorConfig &config = GeneratorConfig()); + void generateSDF(const BitmapRef &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport = true); +void generatePSDF(const BitmapRef &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport = true); void generatePseudoSDF(const BitmapRef &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, bool overlapSupport = true); void generateMSDF(const BitmapRef &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, const ErrorCorrectionConfig &errorCorrectionConfig = ErrorCorrectionConfig(), bool overlapSupport = true); void generateMTSDF(const BitmapRef &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. void generateSDF_legacy(const BitmapRef &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate); +void generatePSDF_legacy(const BitmapRef &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate); void generatePseudoSDF_legacy(const BitmapRef &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate); void generateMSDF_legacy(const BitmapRef &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, ErrorCorrectionConfig errorCorrectionConfig = ErrorCorrectionConfig()); void generateMTSDF_legacy(const BitmapRef &output, const Shape &shape, double range, const Vector2 &scale, const Vector2 &translate, ErrorCorrectionConfig errorCorrectionConfig = ErrorCorrectionConfig());