Skip to content

Commit 08373b4

Browse files
committed
fix: When lines reverse on themselves, mitering could be wrong
If a line reversed direction exactly, mitering logic could render only half the pixels that should have been rendered. In general, when lines nearly reverse on themselves, mitering is tricky. This add some thresholds, below which the lines aren't mitered but are just rendered. For opaque lines, this is a strict improvement, though some joints may no longer show rounded or truncated miters. For semi-transparent lines, this is in general an improvement, but there can be cases where they appear double rendered instead of joined. The behavior is still deemed an improvement, as they should never have only have half the pixels rendered.
1 parent 90ae5d5 commit 08373b4

File tree

1 file changed

+26
-5
lines changed

1 file changed

+26
-5
lines changed

src/webgl/lineFeature.vert

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,27 @@ void main(void)
6262
gl_Position = vec4(2.0, 2.0, 0.0, 1.0);
6363
return;
6464
}
65+
float lineLength = length(vec2(deltaCB.x, deltaCB.y / aspect)) / pixelWidth;
66+
// if lines reverse upon themselves and are not nearly the same length, skip
67+
// joins.
68+
float abLimit = length(vec2(A.x - B.x, (A.y - B.y) / aspect)) / pixelWidth;
69+
float dcLimit = length(vec2(D.x - C.x, (D.y - C.y) / aspect)) / pixelWidth;
70+
if (abLimit >= lineLength - antialiasing - strokeWidth * 0.5 && abLimit <= lineLength + antialiasing + strokeWidth * 0.5) {
71+
abLimit = 0.0001;
72+
} else {
73+
if (abLimit < lineLength) abLimit = lineLength;
74+
abLimit = (strokeWidth - antialiasing) / (abLimit + antialiasing);
75+
if (abLimit < 0.0001) abLimit = 0.0001;
76+
if (abLimit > 0.1) abLimit = 0.1;
77+
}
78+
if (dcLimit >= lineLength - antialiasing - strokeWidth * 0.5 && dcLimit <= lineLength + antialiasing + strokeWidth * 0.5) {
79+
dcLimit = 0.0001;
80+
} else {
81+
if (dcLimit < lineLength) dcLimit = lineLength;
82+
dcLimit = (strokeWidth - antialiasing) / (dcLimit + antialiasing);
83+
if (dcLimit < 0.0001) dcLimit = 0.0001;
84+
if (dcLimit > 0.1) dcLimit = 0.1;
85+
}
6586
float angleCB = atan2(deltaCB.y, deltaCB.x * aspect);
6687
// values we need to pass along
6788
strokeColorVar = vec4(strokeColor, strokeOpacity);
@@ -78,7 +99,7 @@ void main(void)
7899
// by default, offset by the width and don't extend lines. Later,
79100
// calculate line extensions based on end cap and end join modes
80101
float yOffset = strokeWidth + antialiasing;
81-
if (vertex == 0 || vertex == 2) yOffset *= -1.0;
102+
if (vertex == 0) yOffset *= -1.0;
82103
yOffset += strokeWidth * offset;
83104
float xOffset = 0.0;
84105
// end caps
@@ -105,7 +126,8 @@ void main(void)
105126
angleABC = (mod(angleABC + 3.0 * PI, 2.0 * PI) - PI) / 2.0;
106127
cosABC = cos(angleABC); sinABC = sin(angleABC);
107128
// if this angle is close to flat, pass-through the join
108-
if (nearMode >= 4 && cosABC > 0.999999) {
129+
// if the line doubles back exactly, do the same
130+
if (nearMode >= 4 && (cosABC > 0.999999 || cosABC < abLimit)) {
109131
nearMode = 3;
110132
}
111133
// miter, miter-clip
@@ -138,7 +160,8 @@ void main(void)
138160
angleBCD = (mod(angleBCD + 3.0 * PI, 2.0 * PI) - PI) / 2.0;
139161
cosBCD = cos(angleBCD); sinBCD = sin(angleBCD);
140162
// if this angle is close to flat, pass-through the join
141-
if (farMode >= 4 && cosBCD > 0.999999) {
163+
// if the line doubles back exactly, do the same
164+
if (farMode >= 4 && (cosBCD > 0.999999 || cosBCD < dcLimit)) {
142165
farMode = 3;
143166
}
144167
// miter, miter-clip
@@ -159,8 +182,6 @@ void main(void)
159182
B.y + (xOffset * sin(angleCB) + yOffset * cos(angleCB)) * pixelWidth * aspect,
160183
B.z, 1.0);
161184
// store other values needed to determine which pixels to plot.
162-
float lineLength = length(vec2(deltaCB.x, deltaCB.y / aspect)) / pixelWidth;
163-
164185
if (vertex == 0 || vertex == 1) {
165186
subpos = vec4(xOffset, yOffset, lineLength - xOffset, strokeWidth);
166187
info = vec4(float(nearMode), float(farMode), offset, 0.0);

0 commit comments

Comments
 (0)