Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/msdfgen/core/edge-selectors.cpp
20936 views
1
2
#include "edge-selectors.h"
3
4
#include "arithmetics.hpp"
5
6
namespace msdfgen {
7
8
#define DISTANCE_DELTA_FACTOR 1.001
9
10
TrueDistanceSelector::EdgeCache::EdgeCache() : absDistance(0) { }
11
12
void TrueDistanceSelector::reset(const Point2 &p) {
13
double delta = DISTANCE_DELTA_FACTOR*(p-this->p).length();
14
// Since minDistance.distance is initialized to -DBL_MAX, at first glance this seems like it could make it underflow to -infinity, but in practice delta would have to be extremely high for this to happen (above 9e291)
15
minDistance.distance += nonZeroSign(minDistance.distance)*delta;
16
this->p = p;
17
}
18
19
void TrueDistanceSelector::addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge) {
20
double delta = DISTANCE_DELTA_FACTOR*(p-cache.point).length();
21
if (cache.absDistance-delta <= fabs(minDistance.distance)) {
22
double dummy;
23
SignedDistance distance = edge->signedDistance(p, dummy);
24
if (distance < minDistance)
25
minDistance = distance;
26
cache.point = p;
27
cache.absDistance = fabs(distance.distance);
28
}
29
}
30
31
void TrueDistanceSelector::merge(const TrueDistanceSelector &other) {
32
if (other.minDistance < minDistance)
33
minDistance = other.minDistance;
34
}
35
36
TrueDistanceSelector::DistanceType TrueDistanceSelector::distance() const {
37
return minDistance.distance;
38
}
39
40
PerpendicularDistanceSelectorBase::EdgeCache::EdgeCache() : absDistance(0), aDomainDistance(0), bDomainDistance(0), aPerpendicularDistance(0), bPerpendicularDistance(0) { }
41
42
bool PerpendicularDistanceSelectorBase::getPerpendicularDistance(double &distance, const Vector2 &ep, const Vector2 &edgeDir) {
43
double ts = dotProduct(ep, edgeDir);
44
if (ts > 0) {
45
double perpendicularDistance = crossProduct(ep, edgeDir);
46
if (fabs(perpendicularDistance) < fabs(distance)) {
47
distance = perpendicularDistance;
48
return true;
49
}
50
}
51
return false;
52
}
53
54
PerpendicularDistanceSelectorBase::PerpendicularDistanceSelectorBase() : minNegativePerpendicularDistance(-fabs(minTrueDistance.distance)), minPositivePerpendicularDistance(fabs(minTrueDistance.distance)), nearEdge(NULL), nearEdgeParam(0) { }
55
56
void PerpendicularDistanceSelectorBase::reset(double delta) {
57
minTrueDistance.distance += nonZeroSign(minTrueDistance.distance)*delta;
58
minNegativePerpendicularDistance = -fabs(minTrueDistance.distance);
59
minPositivePerpendicularDistance = fabs(minTrueDistance.distance);
60
nearEdge = NULL;
61
nearEdgeParam = 0;
62
}
63
64
bool PerpendicularDistanceSelectorBase::isEdgeRelevant(const EdgeCache &cache, const EdgeSegment *, const Point2 &p) const {
65
double delta = DISTANCE_DELTA_FACTOR*(p-cache.point).length();
66
return (
67
cache.absDistance-delta <= fabs(minTrueDistance.distance) ||
68
fabs(cache.aDomainDistance) < delta ||
69
fabs(cache.bDomainDistance) < delta ||
70
(cache.aDomainDistance > 0 && (cache.aPerpendicularDistance < 0 ?
71
cache.aPerpendicularDistance+delta >= minNegativePerpendicularDistance :
72
cache.aPerpendicularDistance-delta <= minPositivePerpendicularDistance
73
)) ||
74
(cache.bDomainDistance > 0 && (cache.bPerpendicularDistance < 0 ?
75
cache.bPerpendicularDistance+delta >= minNegativePerpendicularDistance :
76
cache.bPerpendicularDistance-delta <= minPositivePerpendicularDistance
77
))
78
);
79
}
80
81
void PerpendicularDistanceSelectorBase::addEdgeTrueDistance(const EdgeSegment *edge, const SignedDistance &distance, double param) {
82
if (distance < minTrueDistance) {
83
minTrueDistance = distance;
84
nearEdge = edge;
85
nearEdgeParam = param;
86
}
87
}
88
89
void PerpendicularDistanceSelectorBase::addEdgePerpendicularDistance(double distance) {
90
if (distance <= 0 && distance > minNegativePerpendicularDistance)
91
minNegativePerpendicularDistance = distance;
92
if (distance >= 0 && distance < minPositivePerpendicularDistance)
93
minPositivePerpendicularDistance = distance;
94
}
95
96
void PerpendicularDistanceSelectorBase::merge(const PerpendicularDistanceSelectorBase &other) {
97
if (other.minTrueDistance < minTrueDistance) {
98
minTrueDistance = other.minTrueDistance;
99
nearEdge = other.nearEdge;
100
nearEdgeParam = other.nearEdgeParam;
101
}
102
if (other.minNegativePerpendicularDistance > minNegativePerpendicularDistance)
103
minNegativePerpendicularDistance = other.minNegativePerpendicularDistance;
104
if (other.minPositivePerpendicularDistance < minPositivePerpendicularDistance)
105
minPositivePerpendicularDistance = other.minPositivePerpendicularDistance;
106
}
107
108
double PerpendicularDistanceSelectorBase::computeDistance(const Point2 &p) const {
109
double minDistance = minTrueDistance.distance < 0 ? minNegativePerpendicularDistance : minPositivePerpendicularDistance;
110
if (nearEdge) {
111
SignedDistance distance = minTrueDistance;
112
nearEdge->distanceToPerpendicularDistance(distance, p, nearEdgeParam);
113
if (fabs(distance.distance) < fabs(minDistance))
114
minDistance = distance.distance;
115
}
116
return minDistance;
117
}
118
119
SignedDistance PerpendicularDistanceSelectorBase::trueDistance() const {
120
return minTrueDistance;
121
}
122
123
void PerpendicularDistanceSelector::reset(const Point2 &p) {
124
double delta = DISTANCE_DELTA_FACTOR*(p-this->p).length();
125
PerpendicularDistanceSelectorBase::reset(delta);
126
this->p = p;
127
}
128
129
void PerpendicularDistanceSelector::addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge) {
130
if (isEdgeRelevant(cache, edge, p)) {
131
double param;
132
SignedDistance distance = edge->signedDistance(p, param);
133
addEdgeTrueDistance(edge, distance, param);
134
cache.point = p;
135
cache.absDistance = fabs(distance.distance);
136
137
Vector2 ap = p-edge->point(0);
138
Vector2 bp = p-edge->point(1);
139
Vector2 aDir = edge->direction(0).normalize(true);
140
Vector2 bDir = edge->direction(1).normalize(true);
141
Vector2 prevDir = prevEdge->direction(1).normalize(true);
142
Vector2 nextDir = nextEdge->direction(0).normalize(true);
143
double add = dotProduct(ap, (prevDir+aDir).normalize(true));
144
double bdd = -dotProduct(bp, (bDir+nextDir).normalize(true));
145
if (add > 0) {
146
double pd = distance.distance;
147
if (getPerpendicularDistance(pd, ap, -aDir))
148
addEdgePerpendicularDistance(pd = -pd);
149
cache.aPerpendicularDistance = pd;
150
}
151
if (bdd > 0) {
152
double pd = distance.distance;
153
if (getPerpendicularDistance(pd, bp, bDir))
154
addEdgePerpendicularDistance(pd);
155
cache.bPerpendicularDistance = pd;
156
}
157
cache.aDomainDistance = add;
158
cache.bDomainDistance = bdd;
159
}
160
}
161
162
PerpendicularDistanceSelector::DistanceType PerpendicularDistanceSelector::distance() const {
163
return computeDistance(p);
164
}
165
166
void MultiDistanceSelector::reset(const Point2 &p) {
167
double delta = DISTANCE_DELTA_FACTOR*(p-this->p).length();
168
r.reset(delta);
169
g.reset(delta);
170
b.reset(delta);
171
this->p = p;
172
}
173
174
void MultiDistanceSelector::addEdge(EdgeCache &cache, const EdgeSegment *prevEdge, const EdgeSegment *edge, const EdgeSegment *nextEdge) {
175
if (
176
(edge->color&RED && r.isEdgeRelevant(cache, edge, p)) ||
177
(edge->color&GREEN && g.isEdgeRelevant(cache, edge, p)) ||
178
(edge->color&BLUE && b.isEdgeRelevant(cache, edge, p))
179
) {
180
double param;
181
SignedDistance distance = edge->signedDistance(p, param);
182
if (edge->color&RED)
183
r.addEdgeTrueDistance(edge, distance, param);
184
if (edge->color&GREEN)
185
g.addEdgeTrueDistance(edge, distance, param);
186
if (edge->color&BLUE)
187
b.addEdgeTrueDistance(edge, distance, param);
188
cache.point = p;
189
cache.absDistance = fabs(distance.distance);
190
191
Vector2 ap = p-edge->point(0);
192
Vector2 bp = p-edge->point(1);
193
Vector2 aDir = edge->direction(0).normalize(true);
194
Vector2 bDir = edge->direction(1).normalize(true);
195
Vector2 prevDir = prevEdge->direction(1).normalize(true);
196
Vector2 nextDir = nextEdge->direction(0).normalize(true);
197
double add = dotProduct(ap, (prevDir+aDir).normalize(true));
198
double bdd = -dotProduct(bp, (bDir+nextDir).normalize(true));
199
if (add > 0) {
200
double pd = distance.distance;
201
if (PerpendicularDistanceSelectorBase::getPerpendicularDistance(pd, ap, -aDir)) {
202
pd = -pd;
203
if (edge->color&RED)
204
r.addEdgePerpendicularDistance(pd);
205
if (edge->color&GREEN)
206
g.addEdgePerpendicularDistance(pd);
207
if (edge->color&BLUE)
208
b.addEdgePerpendicularDistance(pd);
209
}
210
cache.aPerpendicularDistance = pd;
211
}
212
if (bdd > 0) {
213
double pd = distance.distance;
214
if (PerpendicularDistanceSelectorBase::getPerpendicularDistance(pd, bp, bDir)) {
215
if (edge->color&RED)
216
r.addEdgePerpendicularDistance(pd);
217
if (edge->color&GREEN)
218
g.addEdgePerpendicularDistance(pd);
219
if (edge->color&BLUE)
220
b.addEdgePerpendicularDistance(pd);
221
}
222
cache.bPerpendicularDistance = pd;
223
}
224
cache.aDomainDistance = add;
225
cache.bDomainDistance = bdd;
226
}
227
}
228
229
void MultiDistanceSelector::merge(const MultiDistanceSelector &other) {
230
r.merge(other.r);
231
g.merge(other.g);
232
b.merge(other.b);
233
}
234
235
MultiDistanceSelector::DistanceType MultiDistanceSelector::distance() const {
236
MultiDistance multiDistance;
237
multiDistance.r = r.computeDistance(p);
238
multiDistance.g = g.computeDistance(p);
239
multiDistance.b = b.computeDistance(p);
240
return multiDistance;
241
}
242
243
SignedDistance MultiDistanceSelector::trueDistance() const {
244
SignedDistance distance = r.trueDistance();
245
if (g.trueDistance() < distance)
246
distance = g.trueDistance();
247
if (b.trueDistance() < distance)
248
distance = b.trueDistance();
249
return distance;
250
}
251
252
MultiAndTrueDistanceSelector::DistanceType MultiAndTrueDistanceSelector::distance() const {
253
MultiDistance multiDistance = MultiDistanceSelector::distance();
254
MultiAndTrueDistance mtd;
255
mtd.r = multiDistance.r;
256
mtd.g = multiDistance.g;
257
mtd.b = multiDistance.b;
258
mtd.a = trueDistance().distance;
259
return mtd;
260
}
261
262
}
263
264