Skip to content

Commit 64c3e24

Browse files
committed
Renamed pseudo-distance to perpendicular distance
1 parent 35f9254 commit 64c3e24

File tree

10 files changed

+129
-111
lines changed

10 files changed

+129
-111
lines changed

README.md

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ This is a utility for generating signed distance fields from vector shapes and f
44
which serve as a texture representation that can be used in real-time graphics to efficiently reproduce said shapes.
55
Although it can also be used to generate conventional signed distance fields best known from
66
[this Valve paper](https://steamcdn-a.akamaihd.net/apps/valve/2007/SIGGRAPH2007_AlphaTestedMagnification.pdf)
7-
and pseudo-distance fields, its primary purpose is to generate multi-channel distance fields,
7+
and perpendicular distance fields, its primary purpose is to generate multi-channel distance fields,
88
using a method I have developed. Unlike monochrome distance fields, they have the ability
99
to reproduce sharp corners almost perfectly by utilizing all three color channels.
1010

@@ -52,7 +52,7 @@ where only the input specification is required.
5252

5353
Mode can be one of:
5454
- **sdf** – generates a conventional monochrome (true) signed distance field.
55-
- **psdf** – generates a monochrome signed pseudo-distance field.
55+
- **psdf** – generates a monochrome signed perpendicular distance field.
5656
- **msdf** (default) – generates a multi-channel signed distance field using my new method.
5757
- **mtsdf** – generates a combined multi-channel and true signed distance field in the alpha channel.
5858

@@ -104,10 +104,9 @@ in order to generate a distance field. Please note that all classes and function
104104
It consists of closed contours, which in turn consist of edges. An edge is represented by a `LinearEdge`, `QuadraticEdge`,
105105
or `CubicEdge`. You can construct them from two endpoints and 0 to 2 Bézier control points.
106106
- Normalize the shape using its `normalize` method and assign colors to edges if you need a multi-channel SDF.
107-
This can be performed automatically using the `edgeColoringSimple` heuristic, or manually by setting each edge's
108-
`color` member. Keep in mind that at least two color channels must be turned on in each edge, and iff two edges meet
109-
at a sharp corner, they must only have one channel in common.
110-
- Call `generateSDF`, `generatePseudoSDF`, or `generateMSDF` to generate a distance field into a floating point
107+
This can be performed automatically using the `edgeColoringSimple` (or other) heuristic, or manually by setting each edge's
108+
`color` member. Keep in mind that at least two color channels must be turned on in each edge.
109+
- Call `generateSDF`, `generatePSDF`, `generateMSDF`, or `generateMTSDF` to generate a distance field into a floating point
111110
`Bitmap` object. This can then be worked with further or saved to a file using `saveBmp`, `savePng`, or `saveTiff`.
112111
- You may also render an image from the distance field using `renderSDF`. Consider calling `simulate8bit`
113112
on the distance field beforehand to simulate the standard 8 bits/channel image format.

core/MSDFErrorCorrection.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ class ShapeDistanceChecker {
9494
return ArtifactClassifier(this, direction, span);
9595
}
9696
private:
97-
ShapeDistanceFinder<ContourCombiner<PseudoDistanceSelector> > distanceFinder;
97+
ShapeDistanceFinder<ContourCombiner<PerpendicularDistanceSelector> > distanceFinder;
9898
BitmapConstRef<float, N> sdf;
9999
double invRange;
100100
Vector2 texelSize;

core/contour-combiners.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ typename SimpleContourCombiner<EdgeSelector>::DistanceType SimpleContourCombiner
5050
}
5151

5252
template class SimpleContourCombiner<TrueDistanceSelector>;
53-
template class SimpleContourCombiner<PseudoDistanceSelector>;
53+
template class SimpleContourCombiner<PerpendicularDistanceSelector>;
5454
template class SimpleContourCombiner<MultiDistanceSelector>;
5555
template class SimpleContourCombiner<MultiAndTrueDistanceSelector>;
5656

@@ -134,7 +134,7 @@ typename OverlappingContourCombiner<EdgeSelector>::DistanceType OverlappingConto
134134
}
135135

136136
template class OverlappingContourCombiner<TrueDistanceSelector>;
137-
template class OverlappingContourCombiner<PseudoDistanceSelector>;
137+
template class OverlappingContourCombiner<PerpendicularDistanceSelector>;
138138
template class OverlappingContourCombiner<MultiDistanceSelector>;
139139
template class OverlappingContourCombiner<MultiAndTrueDistanceSelector>;
140140

core/edge-segments.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,15 @@ EdgeSegment *EdgeSegment::create(Point2 p0, Point2 p1, Point2 p2, Point2 p3, Edg
2525
return new CubicSegment(p0, p1, p2, p3, edgeColor);
2626
}
2727

28-
void EdgeSegment::distanceToPseudoDistance(SignedDistance &distance, Point2 origin, double param) const {
28+
void EdgeSegment::distanceToPerpendicularDistance(SignedDistance &distance, Point2 origin, double param) const {
2929
if (param < 0) {
3030
Vector2 dir = direction(0).normalize();
3131
Vector2 aq = origin-point(0);
3232
double ts = dotProduct(aq, dir);
3333
if (ts < 0) {
34-
double pseudoDistance = crossProduct(aq, dir);
35-
if (fabs(pseudoDistance) <= fabs(distance.distance)) {
36-
distance.distance = pseudoDistance;
34+
double perpendicularDistance = crossProduct(aq, dir);
35+
if (fabs(perpendicularDistance) <= fabs(distance.distance)) {
36+
distance.distance = perpendicularDistance;
3737
distance.dot = 0;
3838
}
3939
}
@@ -42,9 +42,9 @@ void EdgeSegment::distanceToPseudoDistance(SignedDistance &distance, Point2 orig
4242
Vector2 bq = origin-point(1);
4343
double ts = dotProduct(bq, dir);
4444
if (ts > 0) {
45-
double pseudoDistance = crossProduct(bq, dir);
46-
if (fabs(pseudoDistance) <= fabs(distance.distance)) {
47-
distance.distance = pseudoDistance;
45+
double perpendicularDistance = crossProduct(bq, dir);
46+
if (fabs(perpendicularDistance) <= fabs(distance.distance)) {
47+
distance.distance = perpendicularDistance;
4848
distance.dot = 0;
4949
}
5050
}

core/edge-segments.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ class EdgeSegment {
3737
virtual Vector2 directionChange(double param) const = 0;
3838
/// Returns the minimum signed distance between origin and the edge.
3939
virtual SignedDistance signedDistance(Point2 origin, double &param) const = 0;
40-
/// Converts a previously retrieved signed distance from origin to pseudo-distance.
41-
virtual void distanceToPseudoDistance(SignedDistance &distance, Point2 origin, double param) const;
40+
/// Converts a previously retrieved signed distance from origin to perpendicular distance.
41+
virtual void distanceToPerpendicularDistance(SignedDistance &distance, Point2 origin, double param) const;
4242
/// Outputs a list of (at most three) intersections (their X coordinates) with an infinite horizontal scanline at y and returns how many there are.
4343
virtual int scanlineIntersections(double x[3], int dy[3], double y) const = 0;
4444
/// Adjusts the bounding box to fit the edge segment.

core/edge-selectors.cpp

Lines changed: 51 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -36,96 +36,96 @@ TrueDistanceSelector::DistanceType TrueDistanceSelector::distance() const {
3636
return minDistance.distance;
3737
}
3838

39-
PseudoDistanceSelectorBase::EdgeCache::EdgeCache() : absDistance(0), aDomainDistance(0), bDomainDistance(0), aPseudoDistance(0), bPseudoDistance(0) { }
39+
PerpendicularDistanceSelectorBase::EdgeCache::EdgeCache() : absDistance(0), aDomainDistance(0), bDomainDistance(0), aPerpendicularDistance(0), bPerpendicularDistance(0) { }
4040

41-
bool PseudoDistanceSelectorBase::getPseudoDistance(double &distance, const Vector2 &ep, const Vector2 &edgeDir) {
41+
bool PerpendicularDistanceSelectorBase::getPerpendicularDistance(double &distance, const Vector2 &ep, const Vector2 &edgeDir) {
4242
double ts = dotProduct(ep, edgeDir);
4343
if (ts > 0) {
44-
double pseudoDistance = crossProduct(ep, edgeDir);
45-
if (fabs(pseudoDistance) < fabs(distance)) {
46-
distance = pseudoDistance;
44+
double perpendicularDistance = crossProduct(ep, edgeDir);
45+
if (fabs(perpendicularDistance) < fabs(distance)) {
46+
distance = perpendicularDistance;
4747
return true;
4848
}
4949
}
5050
return false;
5151
}
5252

53-
PseudoDistanceSelectorBase::PseudoDistanceSelectorBase() : minNegativePseudoDistance(-fabs(minTrueDistance.distance)), minPositivePseudoDistance(fabs(minTrueDistance.distance)), nearEdge(NULL), nearEdgeParam(0) { }
53+
PerpendicularDistanceSelectorBase::PerpendicularDistanceSelectorBase() : minNegativePerpendicularDistance(-fabs(minTrueDistance.distance)), minPositivePerpendicularDistance(fabs(minTrueDistance.distance)), nearEdge(NULL), nearEdgeParam(0) { }
5454

55-
void PseudoDistanceSelectorBase::reset(double delta) {
55+
void PerpendicularDistanceSelectorBase::reset(double delta) {
5656
minTrueDistance.distance += nonZeroSign(minTrueDistance.distance)*delta;
57-
minNegativePseudoDistance = -fabs(minTrueDistance.distance);
58-
minPositivePseudoDistance = fabs(minTrueDistance.distance);
57+
minNegativePerpendicularDistance = -fabs(minTrueDistance.distance);
58+
minPositivePerpendicularDistance = fabs(minTrueDistance.distance);
5959
nearEdge = NULL;
6060
nearEdgeParam = 0;
6161
}
6262

63-
bool PseudoDistanceSelectorBase::isEdgeRelevant(const EdgeCache &cache, const EdgeSegment *edge, const Point2 &p) const {
63+
bool PerpendicularDistanceSelectorBase::isEdgeRelevant(const EdgeCache &cache, const EdgeSegment *edge, const Point2 &p) const {
6464
double delta = DISTANCE_DELTA_FACTOR*(p-cache.point).length();
6565
return (
6666
cache.absDistance-delta <= fabs(minTrueDistance.distance) ||
6767
fabs(cache.aDomainDistance) < delta ||
6868
fabs(cache.bDomainDistance) < delta ||
69-
(cache.aDomainDistance > 0 && (cache.aPseudoDistance < 0 ?
70-
cache.aPseudoDistance+delta >= minNegativePseudoDistance :
71-
cache.aPseudoDistance-delta <= minPositivePseudoDistance
69+
(cache.aDomainDistance > 0 && (cache.aPerpendicularDistance < 0 ?
70+
cache.aPerpendicularDistance+delta >= minNegativePerpendicularDistance :
71+
cache.aPerpendicularDistance-delta <= minPositivePerpendicularDistance
7272
)) ||
73-
(cache.bDomainDistance > 0 && (cache.bPseudoDistance < 0 ?
74-
cache.bPseudoDistance+delta >= minNegativePseudoDistance :
75-
cache.bPseudoDistance-delta <= minPositivePseudoDistance
73+
(cache.bDomainDistance > 0 && (cache.bPerpendicularDistance < 0 ?
74+
cache.bPerpendicularDistance+delta >= minNegativePerpendicularDistance :
75+
cache.bPerpendicularDistance-delta <= minPositivePerpendicularDistance
7676
))
7777
);
7878
}
7979

80-
void PseudoDistanceSelectorBase::addEdgeTrueDistance(const EdgeSegment *edge, const SignedDistance &distance, double param) {
80+
void PerpendicularDistanceSelectorBase::addEdgeTrueDistance(const EdgeSegment *edge, const SignedDistance &distance, double param) {
8181
if (distance < minTrueDistance) {
8282
minTrueDistance = distance;
8383
nearEdge = edge;
8484
nearEdgeParam = param;
8585
}
8686
}
8787

88-
void PseudoDistanceSelectorBase::addEdgePseudoDistance(double distance) {
89-
if (distance <= 0 && distance > minNegativePseudoDistance)
90-
minNegativePseudoDistance = distance;
91-
if (distance >= 0 && distance < minPositivePseudoDistance)
92-
minPositivePseudoDistance = distance;
88+
void PerpendicularDistanceSelectorBase::addEdgePerpendicularDistance(double distance) {
89+
if (distance <= 0 && distance > minNegativePerpendicularDistance)
90+
minNegativePerpendicularDistance = distance;
91+
if (distance >= 0 && distance < minPositivePerpendicularDistance)
92+
minPositivePerpendicularDistance = distance;
9393
}
9494

95-
void PseudoDistanceSelectorBase::merge(const PseudoDistanceSelectorBase &other) {
95+
void PerpendicularDistanceSelectorBase::merge(const PerpendicularDistanceSelectorBase &other) {
9696
if (other.minTrueDistance < minTrueDistance) {
9797
minTrueDistance = other.minTrueDistance;
9898
nearEdge = other.nearEdge;
9999
nearEdgeParam = other.nearEdgeParam;
100100
}
101-
if (other.minNegativePseudoDistance > minNegativePseudoDistance)
102-
minNegativePseudoDistance = other.minNegativePseudoDistance;
103-
if (other.minPositivePseudoDistance < minPositivePseudoDistance)
104-
minPositivePseudoDistance = other.minPositivePseudoDistance;
101+
if (other.minNegativePerpendicularDistance > minNegativePerpendicularDistance)
102+
minNegativePerpendicularDistance = other.minNegativePerpendicularDistance;
103+
if (other.minPositivePerpendicularDistance < minPositivePerpendicularDistance)
104+
minPositivePerpendicularDistance = other.minPositivePerpendicularDistance;
105105
}
106106

107-
double PseudoDistanceSelectorBase::computeDistance(const Point2 &p) const {
108-
double minDistance = minTrueDistance.distance < 0 ? minNegativePseudoDistance : minPositivePseudoDistance;
107+
double PerpendicularDistanceSelectorBase::computeDistance(const Point2 &p) const {
108+
double minDistance = minTrueDistance.distance < 0 ? minNegativePerpendicularDistance : minPositivePerpendicularDistance;
109109
if (nearEdge) {
110110
SignedDistance distance = minTrueDistance;
111-
nearEdge->distanceToPseudoDistance(distance, p, nearEdgeParam);
111+
nearEdge->distanceToPerpendicularDistance(distance, p, nearEdgeParam);
112112
if (fabs(distance.distance) < fabs(minDistance))
113113
minDistance = distance.distance;
114114
}
115115
return minDistance;
116116
}
117117

118-
SignedDistance PseudoDistanceSelectorBase::trueDistance() const {
118+
SignedDistance PerpendicularDistanceSelectorBase::trueDistance() const {
119119
return minTrueDistance;
120120
}
121121

122-
void PseudoDistanceSelector::reset(const Point2 &p) {
122+
void PerpendicularDistanceSelector::reset(const Point2 &p) {
123123
double delta = DISTANCE_DELTA_FACTOR*(p-this->p).length();
124-
PseudoDistanceSelectorBase::reset(delta);
124+
PerpendicularDistanceSelectorBase::reset(delta);
125125
this->p = p;
126126
}
127127

128-
void PseudoDistanceSelector::addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge) {
128+
void PerpendicularDistanceSelector::addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge) {
129129
if (isEdgeRelevant(cache, edge, p)) {
130130
double param;
131131
SignedDistance distance = edge->signedDistance(p, param);
@@ -143,22 +143,22 @@ void PseudoDistanceSelector::addEdge(EdgeCache &cache, const EdgeSegment *prevEd
143143
double bdd = -dotProduct(bp, (bDir+nextDir).normalize(true));
144144
if (add > 0) {
145145
double pd = distance.distance;
146-
if (getPseudoDistance(pd, ap, -aDir))
147-
addEdgePseudoDistance(pd = -pd);
148-
cache.aPseudoDistance = pd;
146+
if (getPerpendicularDistance(pd, ap, -aDir))
147+
addEdgePerpendicularDistance(pd = -pd);
148+
cache.aPerpendicularDistance = pd;
149149
}
150150
if (bdd > 0) {
151151
double pd = distance.distance;
152-
if (getPseudoDistance(pd, bp, bDir))
153-
addEdgePseudoDistance(pd);
154-
cache.bPseudoDistance = pd;
152+
if (getPerpendicularDistance(pd, bp, bDir))
153+
addEdgePerpendicularDistance(pd);
154+
cache.bPerpendicularDistance = pd;
155155
}
156156
cache.aDomainDistance = add;
157157
cache.bDomainDistance = bdd;
158158
}
159159
}
160160

161-
PseudoDistanceSelector::DistanceType PseudoDistanceSelector::distance() const {
161+
PerpendicularDistanceSelector::DistanceType PerpendicularDistanceSelector::distance() const {
162162
return computeDistance(p);
163163
}
164164

@@ -197,28 +197,28 @@ void MultiDistanceSelector::addEdge(EdgeCache &cache, const EdgeSegment *prevEdg
197197
double bdd = -dotProduct(bp, (bDir+nextDir).normalize(true));
198198
if (add > 0) {
199199
double pd = distance.distance;
200-
if (PseudoDistanceSelectorBase::getPseudoDistance(pd, ap, -aDir)) {
200+
if (PerpendicularDistanceSelectorBase::getPerpendicularDistance(pd, ap, -aDir)) {
201201
pd = -pd;
202202
if (edge->color&RED)
203-
r.addEdgePseudoDistance(pd);
203+
r.addEdgePerpendicularDistance(pd);
204204
if (edge->color&GREEN)
205-
g.addEdgePseudoDistance(pd);
205+
g.addEdgePerpendicularDistance(pd);
206206
if (edge->color&BLUE)
207-
b.addEdgePseudoDistance(pd);
207+
b.addEdgePerpendicularDistance(pd);
208208
}
209-
cache.aPseudoDistance = pd;
209+
cache.aPerpendicularDistance = pd;
210210
}
211211
if (bdd > 0) {
212212
double pd = distance.distance;
213-
if (PseudoDistanceSelectorBase::getPseudoDistance(pd, bp, bDir)) {
213+
if (PerpendicularDistanceSelectorBase::getPerpendicularDistance(pd, bp, bDir)) {
214214
if (edge->color&RED)
215-
r.addEdgePseudoDistance(pd);
215+
r.addEdgePerpendicularDistance(pd);
216216
if (edge->color&GREEN)
217-
g.addEdgePseudoDistance(pd);
217+
g.addEdgePerpendicularDistance(pd);
218218
if (edge->color&BLUE)
219-
b.addEdgePseudoDistance(pd);
219+
b.addEdgePerpendicularDistance(pd);
220220
}
221-
cache.bPseudoDistance = pd;
221+
cache.bPerpendicularDistance = pd;
222222
}
223223
cache.aDomainDistance = add;
224224
cache.bDomainDistance = bdd;

core/edge-selectors.h

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -38,40 +38,40 @@ class TrueDistanceSelector {
3838

3939
};
4040

41-
class PseudoDistanceSelectorBase {
41+
class PerpendicularDistanceSelectorBase {
4242

4343
public:
4444
struct EdgeCache {
4545
Point2 point;
4646
double absDistance;
4747
double aDomainDistance, bDomainDistance;
48-
double aPseudoDistance, bPseudoDistance;
48+
double aPerpendicularDistance, bPerpendicularDistance;
4949

5050
EdgeCache();
5151
};
5252

53-
static bool getPseudoDistance(double &distance, const Vector2 &ep, const Vector2 &edgeDir);
53+
static bool getPerpendicularDistance(double &distance, const Vector2 &ep, const Vector2 &edgeDir);
5454

55-
PseudoDistanceSelectorBase();
55+
PerpendicularDistanceSelectorBase();
5656
void reset(double delta);
5757
bool isEdgeRelevant(const EdgeCache &cache, const EdgeSegment *edge, const Point2 &p) const;
5858
void addEdgeTrueDistance(const EdgeSegment *edge, const SignedDistance &distance, double param);
59-
void addEdgePseudoDistance(double distance);
60-
void merge(const PseudoDistanceSelectorBase &other);
59+
void addEdgePerpendicularDistance(double distance);
60+
void merge(const PerpendicularDistanceSelectorBase &other);
6161
double computeDistance(const Point2 &p) const;
6262
SignedDistance trueDistance() const;
6363

6464
private:
6565
SignedDistance minTrueDistance;
66-
double minNegativePseudoDistance;
67-
double minPositivePseudoDistance;
66+
double minNegativePerpendicularDistance;
67+
double minPositivePerpendicularDistance;
6868
const EdgeSegment *nearEdge;
6969
double nearEdgeParam;
7070

7171
};
7272

73-
/// Selects the nearest edge by its pseudo-distance.
74-
class PseudoDistanceSelector : public PseudoDistanceSelectorBase {
73+
/// Selects the nearest edge by its perpendicular distance.
74+
class PerpendicularDistanceSelector : public PerpendicularDistanceSelectorBase {
7575

7676
public:
7777
typedef double DistanceType;
@@ -85,12 +85,12 @@ class PseudoDistanceSelector : public PseudoDistanceSelectorBase {
8585

8686
};
8787

88-
/// Selects the nearest edge for each of the three channels by its pseudo-distance.
88+
/// Selects the nearest edge for each of the three channels by its perpendicular distance.
8989
class MultiDistanceSelector {
9090

9191
public:
9292
typedef MultiDistance DistanceType;
93-
typedef PseudoDistanceSelectorBase::EdgeCache EdgeCache;
93+
typedef PerpendicularDistanceSelectorBase::EdgeCache EdgeCache;
9494

9595
void reset(const Point2 &p);
9696
void addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge);
@@ -100,11 +100,11 @@ class MultiDistanceSelector {
100100

101101
private:
102102
Point2 p;
103-
PseudoDistanceSelectorBase r, g, b;
103+
PerpendicularDistanceSelectorBase r, g, b;
104104

105105
};
106106

107-
/// Selects the nearest edge for each of the three color channels by its pseudo-distance and by true distance for the alpha channel.
107+
/// Selects the nearest edge for each of the three color channels by its perpendicular distance and by true distance for the alpha channel.
108108
class MultiAndTrueDistanceSelector : public MultiDistanceSelector {
109109

110110
public:

0 commit comments

Comments
 (0)