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