three-stdlib 2.29.8 → 2.29.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/loaders/SVGLoader.cjs +158 -50
- package/loaders/SVGLoader.cjs.map +1 -1
- package/loaders/SVGLoader.js +158 -50
- package/loaders/SVGLoader.js.map +1 -1
- package/package.json +1 -1
package/loaders/SVGLoader.cjs
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
3
3
|
const THREE = require("three");
|
4
|
+
const COLOR_SPACE_SVG = "srgb";
|
4
5
|
class SVGLoader extends THREE.Loader {
|
5
6
|
constructor(manager) {
|
6
7
|
super(manager);
|
@@ -37,10 +38,11 @@ class SVGLoader extends THREE.Loader {
|
|
37
38
|
if (node.nodeType !== 1)
|
38
39
|
return;
|
39
40
|
const transform = getNodeTransform(node);
|
40
|
-
let
|
41
|
+
let isDefsNode = false;
|
41
42
|
let path = null;
|
42
43
|
switch (node.nodeName) {
|
43
44
|
case "svg":
|
45
|
+
style = parseStyle(node, style);
|
44
46
|
break;
|
45
47
|
case "style":
|
46
48
|
parseCSSStylesheet(node);
|
@@ -78,14 +80,12 @@ class SVGLoader extends THREE.Loader {
|
|
78
80
|
path = parseLineNode(node);
|
79
81
|
break;
|
80
82
|
case "defs":
|
81
|
-
|
82
|
-
break;
|
83
|
-
case "mask":
|
84
|
-
traverseChildNodes = false;
|
83
|
+
isDefsNode = true;
|
85
84
|
break;
|
86
85
|
case "use":
|
87
86
|
style = parseStyle(node, style);
|
88
|
-
const
|
87
|
+
const href = node.getAttributeNS("http://www.w3.org/1999/xlink", "href") || "";
|
88
|
+
const usedNodeId = href.substring(1);
|
89
89
|
const usedNode = node.viewportElement.getElementById(usedNodeId);
|
90
90
|
if (usedNode) {
|
91
91
|
parseNode(usedNode, style);
|
@@ -96,17 +96,19 @@ class SVGLoader extends THREE.Loader {
|
|
96
96
|
}
|
97
97
|
if (path) {
|
98
98
|
if (style.fill !== void 0 && style.fill !== "none") {
|
99
|
-
path.color.setStyle(style.fill);
|
99
|
+
path.color.setStyle(style.fill, COLOR_SPACE_SVG);
|
100
100
|
}
|
101
101
|
transformPath(path, currentTransform);
|
102
102
|
paths.push(path);
|
103
103
|
path.userData = { node, style };
|
104
104
|
}
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
105
|
+
const childNodes = node.childNodes;
|
106
|
+
for (let i = 0; i < childNodes.length; i++) {
|
107
|
+
const node2 = childNodes[i];
|
108
|
+
if (isDefsNode && node2.nodeName !== "style" && node2.nodeName !== "defs") {
|
109
|
+
continue;
|
109
110
|
}
|
111
|
+
parseNode(node2, style);
|
110
112
|
}
|
111
113
|
if (transform) {
|
112
114
|
transformStack.pop();
|
@@ -125,11 +127,13 @@ class SVGLoader extends THREE.Loader {
|
|
125
127
|
let isFirstPoint = true;
|
126
128
|
let doSetFirstPoint = false;
|
127
129
|
const d = node.getAttribute("d");
|
130
|
+
if (d === "" || d === "none")
|
131
|
+
return null;
|
128
132
|
const commands = d.match(/[a-df-z][^a-df-z]*/gi);
|
129
133
|
for (let i = 0, l = commands.length; i < l; i++) {
|
130
134
|
const command = commands[i];
|
131
135
|
const type = command.charAt(0);
|
132
|
-
const data2 = command.
|
136
|
+
const data2 = command.slice(1).trim();
|
133
137
|
if (isFirstPoint === true) {
|
134
138
|
doSetFirstPoint = true;
|
135
139
|
isFirstPoint = false;
|
@@ -442,7 +446,8 @@ class SVGLoader extends THREE.Loader {
|
|
442
446
|
continue;
|
443
447
|
const selectorList = stylesheet.selectorText.split(/,/gm).filter(Boolean).map((i2) => i2.trim());
|
444
448
|
for (let j = 0; j < selectorList.length; j++) {
|
445
|
-
|
449
|
+
const definitions = Object.fromEntries(Object.entries(stylesheet.style).filter(([, v]) => v !== ""));
|
450
|
+
stylesheets[selectorList[j]] = Object.assign(stylesheets[selectorList[j]] || {}, definitions);
|
446
451
|
}
|
447
452
|
}
|
448
453
|
}
|
@@ -530,7 +535,7 @@ class SVGLoader extends THREE.Loader {
|
|
530
535
|
}
|
531
536
|
index++;
|
532
537
|
}
|
533
|
-
const regex = /(
|
538
|
+
const regex = /([+-]?\d*\.?\d+(?:e[+-]?\d+)?)(?:,|\s)([+-]?\d*\.?\d+(?:e[+-]?\d+)?)/g;
|
534
539
|
const path = new THREE.ShapePath();
|
535
540
|
let index = 0;
|
536
541
|
node.getAttribute("points").replace(regex, iterator);
|
@@ -548,7 +553,7 @@ class SVGLoader extends THREE.Loader {
|
|
548
553
|
}
|
549
554
|
index++;
|
550
555
|
}
|
551
|
-
const regex = /(
|
556
|
+
const regex = /([+-]?\d*\.?\d+(?:e[+-]?\d+)?)(?:,|\s)([+-]?\d*\.?\d+(?:e[+-]?\d+)?)/g;
|
552
557
|
const path = new THREE.ShapePath();
|
553
558
|
let index = 0;
|
554
559
|
node.getAttribute("points").replace(regex, iterator);
|
@@ -600,13 +605,12 @@ class SVGLoader extends THREE.Loader {
|
|
600
605
|
stylesheetStyles = Object.assign(stylesheetStyles, stylesheets["#" + node.getAttribute("id")]);
|
601
606
|
}
|
602
607
|
function addStyle(svgName, jsName, adjustFunction) {
|
603
|
-
if (adjustFunction === void 0)
|
608
|
+
if (adjustFunction === void 0)
|
604
609
|
adjustFunction = function copy(v) {
|
605
610
|
if (v.startsWith("url"))
|
606
611
|
console.warn("SVGLoader: url access in attributes is not implemented.");
|
607
612
|
return v;
|
608
613
|
};
|
609
|
-
}
|
610
614
|
if (node.hasAttribute(svgName))
|
611
615
|
style[jsName] = adjustFunction(node.getAttribute(svgName));
|
612
616
|
if (stylesheetStyles[svgName])
|
@@ -871,14 +875,14 @@ class SVGLoader extends THREE.Loader {
|
|
871
875
|
const openParPos = transformText.indexOf("(");
|
872
876
|
const closeParPos = transformText.length;
|
873
877
|
if (openParPos > 0 && openParPos < closeParPos) {
|
874
|
-
const transformType = transformText.
|
875
|
-
const array = parseFloats(transformText.
|
878
|
+
const transformType = transformText.slice(0, openParPos);
|
879
|
+
const array = parseFloats(transformText.slice(openParPos + 1));
|
876
880
|
currentTransform2.identity();
|
877
881
|
switch (transformType) {
|
878
882
|
case "translate":
|
879
883
|
if (array.length >= 1) {
|
880
884
|
const tx = array[0];
|
881
|
-
let ty =
|
885
|
+
let ty = 0;
|
882
886
|
if (array.length >= 2) {
|
883
887
|
ty = array[1];
|
884
888
|
}
|
@@ -890,15 +894,15 @@ class SVGLoader extends THREE.Loader {
|
|
890
894
|
let angle = 0;
|
891
895
|
let cx = 0;
|
892
896
|
let cy = 0;
|
893
|
-
angle =
|
897
|
+
angle = array[0] * Math.PI / 180;
|
894
898
|
if (array.length >= 3) {
|
895
899
|
cx = array[1];
|
896
900
|
cy = array[2];
|
897
901
|
}
|
898
|
-
tempTransform1.
|
899
|
-
tempTransform2.
|
902
|
+
tempTransform1.makeTranslation(-cx, -cy);
|
903
|
+
tempTransform2.makeRotation(angle);
|
900
904
|
tempTransform3.multiplyMatrices(tempTransform2, tempTransform1);
|
901
|
-
tempTransform1.
|
905
|
+
tempTransform1.makeTranslation(cx, cy);
|
902
906
|
currentTransform2.multiplyMatrices(tempTransform1, tempTransform3);
|
903
907
|
}
|
904
908
|
break;
|
@@ -939,7 +943,55 @@ class SVGLoader extends THREE.Loader {
|
|
939
943
|
tempV3.set(v2.x, v2.y, 1).applyMatrix3(m);
|
940
944
|
v2.set(tempV3.x, tempV3.y);
|
941
945
|
}
|
942
|
-
|
946
|
+
function transfEllipseGeneric(curve) {
|
947
|
+
const a = curve.xRadius;
|
948
|
+
const b = curve.yRadius;
|
949
|
+
const cosTheta = Math.cos(curve.aRotation);
|
950
|
+
const sinTheta = Math.sin(curve.aRotation);
|
951
|
+
const v1 = new THREE.Vector3(a * cosTheta, a * sinTheta, 0);
|
952
|
+
const v2 = new THREE.Vector3(-b * sinTheta, b * cosTheta, 0);
|
953
|
+
const f1 = v1.applyMatrix3(m);
|
954
|
+
const f2 = v2.applyMatrix3(m);
|
955
|
+
const mF = tempTransform0.set(f1.x, f2.x, 0, f1.y, f2.y, 0, 0, 0, 1);
|
956
|
+
const mFInv = tempTransform1.copy(mF).invert();
|
957
|
+
const mFInvT = tempTransform2.copy(mFInv).transpose();
|
958
|
+
const mQ = mFInvT.multiply(mFInv);
|
959
|
+
const mQe = mQ.elements;
|
960
|
+
const ed = eigenDecomposition(mQe[0], mQe[1], mQe[4]);
|
961
|
+
const rt1sqrt = Math.sqrt(ed.rt1);
|
962
|
+
const rt2sqrt = Math.sqrt(ed.rt2);
|
963
|
+
curve.xRadius = 1 / rt1sqrt;
|
964
|
+
curve.yRadius = 1 / rt2sqrt;
|
965
|
+
curve.aRotation = Math.atan2(ed.sn, ed.cs);
|
966
|
+
const isFullEllipse = (curve.aEndAngle - curve.aStartAngle) % (2 * Math.PI) < Number.EPSILON;
|
967
|
+
if (!isFullEllipse) {
|
968
|
+
const mDsqrt = tempTransform1.set(rt1sqrt, 0, 0, 0, rt2sqrt, 0, 0, 0, 1);
|
969
|
+
const mRT = tempTransform2.set(ed.cs, ed.sn, 0, -ed.sn, ed.cs, 0, 0, 0, 1);
|
970
|
+
const mDRF = mDsqrt.multiply(mRT).multiply(mF);
|
971
|
+
const transformAngle = (phi) => {
|
972
|
+
const { x: cosR, y: sinR } = new THREE.Vector3(Math.cos(phi), Math.sin(phi), 0).applyMatrix3(mDRF);
|
973
|
+
return Math.atan2(sinR, cosR);
|
974
|
+
};
|
975
|
+
curve.aStartAngle = transformAngle(curve.aStartAngle);
|
976
|
+
curve.aEndAngle = transformAngle(curve.aEndAngle);
|
977
|
+
if (isTransformFlipped(m)) {
|
978
|
+
curve.aClockwise = !curve.aClockwise;
|
979
|
+
}
|
980
|
+
}
|
981
|
+
}
|
982
|
+
function transfEllipseNoSkew(curve) {
|
983
|
+
const sx = getTransformScaleX(m);
|
984
|
+
const sy = getTransformScaleY(m);
|
985
|
+
curve.xRadius *= sx;
|
986
|
+
curve.yRadius *= sy;
|
987
|
+
const theta = sx > Number.EPSILON ? Math.atan2(m.elements[1], m.elements[0]) : Math.atan2(-m.elements[3], m.elements[4]);
|
988
|
+
curve.aRotation += theta;
|
989
|
+
if (isTransformFlipped(m)) {
|
990
|
+
curve.aStartAngle *= -1;
|
991
|
+
curve.aEndAngle *= -1;
|
992
|
+
curve.aClockwise = !curve.aClockwise;
|
993
|
+
}
|
994
|
+
}
|
943
995
|
const subPaths = path.subPaths;
|
944
996
|
for (let i = 0, n = subPaths.length; i < n; i++) {
|
945
997
|
const subPath = subPaths[i];
|
@@ -959,21 +1011,31 @@ class SVGLoader extends THREE.Loader {
|
|
959
1011
|
transfVec2(curve.v1);
|
960
1012
|
transfVec2(curve.v2);
|
961
1013
|
} else if (curve.isEllipseCurve) {
|
962
|
-
if (isRotated) {
|
963
|
-
console.warn("SVGLoader: Elliptic arc or ellipse rotation or skewing is not implemented.");
|
964
|
-
}
|
965
1014
|
tempV2.set(curve.aX, curve.aY);
|
966
1015
|
transfVec2(tempV2);
|
967
1016
|
curve.aX = tempV2.x;
|
968
1017
|
curve.aY = tempV2.y;
|
969
|
-
|
970
|
-
|
1018
|
+
if (isTransformSkewed(m)) {
|
1019
|
+
transfEllipseGeneric(curve);
|
1020
|
+
} else {
|
1021
|
+
transfEllipseNoSkew(curve);
|
1022
|
+
}
|
971
1023
|
}
|
972
1024
|
}
|
973
1025
|
}
|
974
1026
|
}
|
975
|
-
function
|
976
|
-
|
1027
|
+
function isTransformFlipped(m) {
|
1028
|
+
const te = m.elements;
|
1029
|
+
return te[0] * te[4] - te[1] * te[3] < 0;
|
1030
|
+
}
|
1031
|
+
function isTransformSkewed(m) {
|
1032
|
+
const te = m.elements;
|
1033
|
+
const basisDot = te[0] * te[3] + te[1] * te[4];
|
1034
|
+
if (basisDot === 0)
|
1035
|
+
return false;
|
1036
|
+
const sx = getTransformScaleX(m);
|
1037
|
+
const sy = getTransformScaleY(m);
|
1038
|
+
return Math.abs(basisDot / (sx * sy)) > Number.EPSILON;
|
977
1039
|
}
|
978
1040
|
function getTransformScaleX(m) {
|
979
1041
|
const te = m.elements;
|
@@ -983,6 +1045,45 @@ class SVGLoader extends THREE.Loader {
|
|
983
1045
|
const te = m.elements;
|
984
1046
|
return Math.sqrt(te[3] * te[3] + te[4] * te[4]);
|
985
1047
|
}
|
1048
|
+
function eigenDecomposition(A, B, C) {
|
1049
|
+
let rt1, rt2, cs, sn, t;
|
1050
|
+
const sm = A + C;
|
1051
|
+
const df = A - C;
|
1052
|
+
const rt = Math.sqrt(df * df + 4 * B * B);
|
1053
|
+
if (sm > 0) {
|
1054
|
+
rt1 = 0.5 * (sm + rt);
|
1055
|
+
t = 1 / rt1;
|
1056
|
+
rt2 = A * t * C - B * t * B;
|
1057
|
+
} else if (sm < 0) {
|
1058
|
+
rt2 = 0.5 * (sm - rt);
|
1059
|
+
} else {
|
1060
|
+
rt1 = 0.5 * rt;
|
1061
|
+
rt2 = -0.5 * rt;
|
1062
|
+
}
|
1063
|
+
if (df > 0) {
|
1064
|
+
cs = df + rt;
|
1065
|
+
} else {
|
1066
|
+
cs = df - rt;
|
1067
|
+
}
|
1068
|
+
if (Math.abs(cs) > 2 * Math.abs(B)) {
|
1069
|
+
t = -2 * B / cs;
|
1070
|
+
sn = 1 / Math.sqrt(1 + t * t);
|
1071
|
+
cs = t * sn;
|
1072
|
+
} else if (Math.abs(B) === 0) {
|
1073
|
+
cs = 1;
|
1074
|
+
sn = 0;
|
1075
|
+
} else {
|
1076
|
+
t = -0.5 * cs / B;
|
1077
|
+
cs = 1 / Math.sqrt(1 + t * t);
|
1078
|
+
sn = t * cs;
|
1079
|
+
}
|
1080
|
+
if (df > 0) {
|
1081
|
+
t = cs;
|
1082
|
+
cs = -sn;
|
1083
|
+
sn = t;
|
1084
|
+
}
|
1085
|
+
return { rt1, rt2, cs, sn };
|
1086
|
+
}
|
986
1087
|
const paths = [];
|
987
1088
|
const stylesheets = {};
|
988
1089
|
const transformStack = [];
|
@@ -1182,13 +1283,13 @@ class SVGLoader extends THREE.Loader {
|
|
1182
1283
|
let isHoleFor = null;
|
1183
1284
|
let lastCWValue = null;
|
1184
1285
|
for (let i2 = 0; i2 < stack.length; i2++) {
|
1185
|
-
const
|
1286
|
+
const identifier = stack[i2];
|
1186
1287
|
if (isHole) {
|
1187
|
-
lastCWValue = allPaths[
|
1288
|
+
lastCWValue = allPaths[identifier].isCW;
|
1188
1289
|
isHole = false;
|
1189
|
-
isHoleFor =
|
1190
|
-
} else if (lastCWValue !== allPaths[
|
1191
|
-
lastCWValue = allPaths[
|
1290
|
+
isHoleFor = identifier;
|
1291
|
+
} else if (lastCWValue !== allPaths[identifier].isCW) {
|
1292
|
+
lastCWValue = allPaths[identifier].isCW;
|
1192
1293
|
isHole = true;
|
1193
1294
|
}
|
1194
1295
|
}
|
@@ -1197,7 +1298,6 @@ class SVGLoader extends THREE.Loader {
|
|
1197
1298
|
console.warn('fill-rule: "' + _fillRule + '" is currently not implemented.');
|
1198
1299
|
}
|
1199
1300
|
}
|
1200
|
-
let identifier = 0;
|
1201
1301
|
let scanlineMinX = BIGNUMBER;
|
1202
1302
|
let scanlineMaxX = -BIGNUMBER;
|
1203
1303
|
let simplePaths = shapePath.subPaths.map((p) => {
|
@@ -1231,13 +1331,22 @@ class SVGLoader extends THREE.Loader {
|
|
1231
1331
|
curves: p.curves,
|
1232
1332
|
points,
|
1233
1333
|
isCW: THREE.ShapeUtils.isClockWise(points),
|
1234
|
-
identifier:
|
1334
|
+
identifier: -1,
|
1235
1335
|
boundingBox: new THREE.Box2(new THREE.Vector2(minX, minY), new THREE.Vector2(maxX, maxY))
|
1236
1336
|
};
|
1237
1337
|
});
|
1238
1338
|
simplePaths = simplePaths.filter((sp) => sp.points.length > 1);
|
1339
|
+
for (let identifier = 0; identifier < simplePaths.length; identifier++) {
|
1340
|
+
simplePaths[identifier].identifier = identifier;
|
1341
|
+
}
|
1239
1342
|
const isAHole = simplePaths.map(
|
1240
|
-
(p) => isHoleTo(
|
1343
|
+
(p) => isHoleTo(
|
1344
|
+
p,
|
1345
|
+
simplePaths,
|
1346
|
+
scanlineMinX,
|
1347
|
+
scanlineMaxX,
|
1348
|
+
shapePath.userData ? shapePath.userData.style.fillRule : void 0
|
1349
|
+
)
|
1241
1350
|
);
|
1242
1351
|
const shapesToReturn = [];
|
1243
1352
|
simplePaths.forEach((p) => {
|
@@ -1333,9 +1442,8 @@ class SVGLoader extends THREE.Loader {
|
|
1333
1442
|
if (iPoint === numPoints - 1) {
|
1334
1443
|
if (isClosed) {
|
1335
1444
|
nextPoint = points[1];
|
1336
|
-
} else
|
1445
|
+
} else
|
1337
1446
|
nextPoint = void 0;
|
1338
|
-
}
|
1339
1447
|
} else {
|
1340
1448
|
nextPoint = points[iPoint + 1];
|
1341
1449
|
}
|
@@ -1361,7 +1469,7 @@ class SVGLoader extends THREE.Loader {
|
|
1361
1469
|
tempV2_3.subVectors(nextPoint, currentPoint);
|
1362
1470
|
tempV2_3.normalize();
|
1363
1471
|
const dot = Math.abs(normal1.dot(tempV2_3));
|
1364
|
-
if (dot
|
1472
|
+
if (dot > Number.EPSILON) {
|
1365
1473
|
const miterSide = strokeWidth2 / dot;
|
1366
1474
|
tempV2_3.multiplyScalar(-miterSide);
|
1367
1475
|
tempV2_4.subVectors(currentPoint, previousPoint);
|
@@ -1571,8 +1679,8 @@ class SVGLoader extends THREE.Loader {
|
|
1571
1679
|
addVertex(lastPointL, u0, 0);
|
1572
1680
|
addVertex(currentPointL, u1, 0);
|
1573
1681
|
addVertex(lastPointR, u0, 1);
|
1574
|
-
addVertex(currentPointL, u1,
|
1575
|
-
addVertex(currentPointR, u1,
|
1682
|
+
addVertex(currentPointL, u1, 0);
|
1683
|
+
addVertex(currentPointR, u1, 1);
|
1576
1684
|
}
|
1577
1685
|
function makeSegmentWithBevelJoin(joinIsOnLeftSide2, innerSideModified2, u) {
|
1578
1686
|
if (innerSideModified2) {
|
@@ -1594,8 +1702,8 @@ class SVGLoader extends THREE.Loader {
|
|
1594
1702
|
addVertex(innerPoint, u1, 0);
|
1595
1703
|
addVertex(currentPointR, u1, 1);
|
1596
1704
|
addVertex(currentPointR, u, 1);
|
1597
|
-
addVertex(
|
1598
|
-
addVertex(
|
1705
|
+
addVertex(innerPoint, u, 0);
|
1706
|
+
addVertex(nextPointR, u, 1);
|
1599
1707
|
}
|
1600
1708
|
} else {
|
1601
1709
|
if (joinIsOnLeftSide2) {
|
@@ -1661,7 +1769,7 @@ class SVGLoader extends THREE.Loader {
|
|
1661
1769
|
tempV2_4.toArray(vertices, 3 * 3);
|
1662
1770
|
} else {
|
1663
1771
|
tempV2_3.toArray(vertices, 1 * 3);
|
1664
|
-
tempV2_3.toArray(vertices, 3 * 3);
|
1772
|
+
uvs[3 * 2 + 1] === 1 ? tempV2_4.toArray(vertices, 3 * 3) : tempV2_3.toArray(vertices, 3 * 3);
|
1665
1773
|
tempV2_4.toArray(vertices, 0 * 3);
|
1666
1774
|
}
|
1667
1775
|
} else {
|
@@ -1675,8 +1783,8 @@ class SVGLoader extends THREE.Loader {
|
|
1675
1783
|
tempV2_4.toArray(vertices, vl - 2 * 3);
|
1676
1784
|
tempV2_4.toArray(vertices, vl - 4 * 3);
|
1677
1785
|
} else {
|
1678
|
-
|
1679
|
-
|
1786
|
+
tempV2_4.toArray(vertices, vl - 2 * 3);
|
1787
|
+
tempV2_3.toArray(vertices, vl - 1 * 3);
|
1680
1788
|
tempV2_4.toArray(vertices, vl - 4 * 3);
|
1681
1789
|
}
|
1682
1790
|
}
|