Skip to content

Commit 9c35ac1

Browse files
lasselammigithub-actions[bot]
authored andcommitted
Fix elevated line bevel join artifacts at sharp corners (internal-9688)
GitOrigin-RevId: 1c87f6f9c9f785add80f9cb1716769c9a5cf18ca
1 parent 3ca4028 commit 9c35ac1

58 files changed

Lines changed: 174 additions & 7 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/data/bucket/line_bucket.ts

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,11 @@ const COS_STRAIGHT_CORNER = Math.cos(5 * (Math.PI / 180));
8686
// Angle per triangle for approximating round line joins.
8787
const DEG_PER_TRIANGLE = 20;
8888

89+
// Multiplier for sharpCornerOffset to determine the threshold distance where
90+
// cap scaling begins for elevated bevel joins. Caps are scaled down linearly
91+
// when segment length is below this threshold to prevent overlap artifacts.
92+
const CAP_SCALE_THRESHOLD_FACTOR = 4.0;
93+
8994
type LineClips = {
9095
start: number;
9196
end: number;
@@ -130,6 +135,7 @@ class LineBucket implements Bucket {
130135
e2: number;
131136

132137
patternJoinNone: boolean;
138+
currentLineJoinType: string;
133139
segmentStart: number;
134140
segmentStartf32: number;
135141
segmentPoints: Array<number>;
@@ -630,6 +636,7 @@ class LineBucket implements Bucket {
630636

631637
const joinNone = join === 'none';
632638
this.patternJoinNone = this.hasPattern && joinNone;
639+
this.currentLineJoinType = join;
633640
this.segmentStart = 0;
634641
this.segmentStartf32 = 0;
635642
this.segmentPoints = [];
@@ -906,12 +913,28 @@ class LineBucket implements Bucket {
906913
this.addCurrentVertex(currentVertex, joinNormal.mult(-1), 0, 0, segment, lineProgressFeatures);
907914

908915
} else if (currentJoin === 'bevel' || currentJoin === 'fakeround') {
916+
const dist = currentVertex.dist(prevVertex);
917+
918+
// Special handling for elevated bevel joins only
919+
const isElevatedBevel = this.elevationType === 'offset' &&
920+
currentJoin === 'bevel' &&
921+
this.currentLineJoinType !== 'round' &&
922+
!this.patternJoinNone;
923+
924+
// For elevated bevel joins at close corners, scale down rotation to prevent overlap
925+
let capScale = 1.0;
926+
if (isElevatedBevel && lineProgressFeatures != null && prevVertex && nextVertex) {
927+
const widthThreshold = CAP_SCALE_THRESHOLD_FACTOR * sharpCornerOffset;
928+
if (dist < widthThreshold) {
929+
capScale = Math.max(0.0, dist / widthThreshold);
930+
}
931+
}
932+
909933
if (lineProgressFeatures != null && prevVertex) {
910934
// Close previous segment with butt
911-
this.addCurrentVertex(currentVertex, endNormal ? endNormal : prevNormal, -1, -1, segment, lineProgressFeatures);
935+
this.addCurrentVertex(currentVertex, endNormal ? endNormal : prevNormal, -capScale, -capScale, segment, lineProgressFeatures);
912936
}
913937

914-
const dist = currentVertex.dist(prevVertex);
915938
const skipStraightEdges = dist <= 2 * sharpCornerOffset && currentJoin !== 'bevel';
916939
const join = joinNormal.mult(lineTurnsLeft ? 1.0 : -1.0);
917940
join._mult(miterLength);
@@ -961,7 +984,7 @@ class LineBucket implements Bucket {
961984

962985
if (lineProgressFeatures != null && nextVertex) {
963986
// Start next segment with a butt
964-
this.addCurrentVertex(currentVertex, startNormal ? startNormal : nextNormal, 1, 1, segment, lineProgressFeatures);
987+
this.addCurrentVertex(currentVertex, startNormal ? startNormal : nextNormal, capScale, capScale, segment, lineProgressFeatures);
965988
}
966989
} else if (currentJoin === 'butt') {
967990
this.addCurrentVertex(currentVertex, joinNormal, 0, 0, segment, lineProgressFeatures); // butt cap
@@ -1022,6 +1045,21 @@ class LineBucket implements Bucket {
10221045
const stepY = (to.y - from.y) / steps;
10231046
const stepZ = (to.z - from.z) / steps;
10241047
const stepW = (to.w - from.w) / steps;
1048+
1049+
// Calculate perpendicular normal directly from segment direction for interior vertices
1050+
const dx = to.x - from.x;
1051+
const dy = to.y - from.y;
1052+
const len = Math.sqrt(dx * dx + dy * dy);
1053+
// Degenerate segment, skip tessellation
1054+
if (len === 0) return;
1055+
1056+
const perpX = -dy / len;
1057+
const perpY = dx / len;
1058+
const interiorLeftX = perpX;
1059+
const interiorLeftY = perpY;
1060+
const interiorRightX = -perpX;
1061+
const interiorRightY = -perpY;
1062+
10251063
for (let i = 1; i < steps; ++i) {
10261064
from.x += stepX;
10271065
from.y += stepY;
@@ -1030,13 +1068,15 @@ class LineBucket implements Bucket {
10301068
stepsDistance += stepW;
10311069
const lpf = this.evaluateLineProgressFeatures(this.prevDistance + stepsDistance);
10321070
this.scaledDistance = (this.prevDistance + stepsDistance) / this.totalDistance;
1033-
this.addHalfVertex(from, leftX, leftY, round, false, endLeft, segment, lpf);
1034-
this.addHalfVertex(from, rightX, rightY, round, true, -endRight, segment, lpf);
1071+
// Use perpendicular extrusion for interior vertices
1072+
this.addHalfVertex(from, interiorLeftX, interiorLeftY, round, false, 0, segment, lpf);
1073+
this.addHalfVertex(from, interiorRightX, interiorRightY, round, true, 0, segment, lpf);
10351074
}
10361075
}
10371076
this.lineSoFar = to.w;
10381077
this.scaledDistance = scaledDistance;
10391078
const lpf = this.evaluateLineProgressFeatures(this.distance);
1079+
10401080
this.addHalfVertex(to, leftX, leftY, round, false, endLeft, segment, lpf);
10411081
this.addHalfVertex(to, rightX, rightY, round, true, -endRight, segment, lpf);
10421082
}
@@ -1097,8 +1137,9 @@ class LineBucket implements Bucket {
10971137

10981138
if (lineProgressFeatures != null) {
10991139
const dropOutOfBounds = this.elevationType === 'offset';
1100-
const boundsMin = -10;
1101-
const boundsMax = EXTENT + 10;
1140+
const clipMargin = this.elevationType === 'offset' ? 2 : 10;
1141+
const boundsMin = -clipMargin;
1142+
const boundsMax = EXTENT + clipMargin;
11021143
const zOffset = lineProgressFeatures.zOffset;
11031144
const vertex = new Point4D(p.x, p.y, zOffset, this.lineSoFar);
11041145
// tesellated chunks outside tile borders are not added.
59.7 KB
-32.9 KB
12 KB
7.52 KB
7.52 KB
9.41 KB
8.03 KB
2.25 KB
3.77 KB

0 commit comments

Comments
 (0)