Skip to content

Commit 9196184

Browse files
authored
SVGLoader: Make stroke generation more robust. (#33438)
1 parent 59739a3 commit 9196184

3 files changed

Lines changed: 48 additions & 0 deletions

File tree

examples/jsm/loaders/SVGLoader.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2663,6 +2663,22 @@ class SVGLoader extends Loader {
26632663
outerPoint.copy( tempV2_5 ).add( currentPoint );
26642664
innerPoint.add( currentPoint );
26652665

2666+
// in-loop fold detection to mitigate #25326
2667+
if ( innerSideModified ) {
2668+
2669+
// when the second triangle's signed area would flip, snap innerPoint to the previous inner-side vertex
2670+
2671+
const refPt = joinIsOnLeftSide ? lastPointR : lastPointL;
2672+
const foldCross = ( outerPoint.x - refPt.x ) * ( innerPoint.y - refPt.y )
2673+
- ( outerPoint.y - refPt.y ) * ( innerPoint.x - refPt.x );
2674+
if ( ( joinIsOnLeftSide && foldCross < 0 ) || ( ! joinIsOnLeftSide && foldCross > 0 ) ) {
2675+
2676+
innerPoint.copy( refPt );
2677+
2678+
}
2679+
2680+
}
2681+
26662682
isMiter = false;
26672683

26682684
if ( innerSideModified ) {
@@ -2941,6 +2957,32 @@ class SVGLoader extends Loader {
29412957

29422958
}
29432959

2960+
// Second fix for #25326: Scan for reamining flipped (CW) triangles and collapse them to
2961+
// degenerated ones. This is safe and leaves no "holes" in the stroke because the flipped
2962+
// triangle's area is covered by neighbouring (CCW) triangles.
2963+
2964+
if ( vertices ) {
2965+
2966+
const tri = [ new Vector2(), new Vector2(), new Vector2() ];
2967+
const startFloat = vertexOffset * 3;
2968+
2969+
for ( let t = startFloat; t < currentCoordinate; t += 9 ) {
2970+
2971+
tri[ 0 ].set( vertices[ t ], vertices[ t + 1 ] );
2972+
tri[ 1 ].set( vertices[ t + 3 ], vertices[ t + 4 ] );
2973+
tri[ 2 ].set( vertices[ t + 6 ], vertices[ t + 7 ] );
2974+
2975+
if ( ShapeUtils.area( tri ) < 0 ) {
2976+
2977+
vertices[ t + 3 ] = tri[ 0 ].x;
2978+
vertices[ t + 4 ] = tri[ 0 ].y;
2979+
2980+
}
2981+
2982+
}
2983+
2984+
}
2985+
29442986
return numVertices;
29452987

29462988
// -- End of algorithm
Lines changed: 4 additions & 0 deletions
Loading

examples/webgl_loader_svg.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@
122122
'emptyPath': 'models/svg/emptyPath.svg',
123123
'emoji': 'models/svg/emoji.svg',
124124
'blueprint': 'models/svg/blueprint.svg',
125+
'wideStroke': 'models/svg/tests/wideStroke.svg',
125126

126127
} ).name( 'SVG File' ).onChange( update );
127128

@@ -205,6 +206,7 @@
205206
if ( material ) {
206207

207208
material.wireframe = guiData.strokesWireframe;
209+
material.side = 0;
208210

209211
for ( const subPath of path.subPaths ) {
210212

0 commit comments

Comments
 (0)