three-stdlib 2.29.8 → 2.29.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -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 traverseChildNodes = true;
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
- traverseChildNodes = false;
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 usedNodeId = node.href.baseVal.substring(1);
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
- if (traverseChildNodes) {
106
- const nodes = node.childNodes;
107
- for (let i = 0; i < nodes.length; i++) {
108
- parseNode(nodes[i], style);
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.substr(1).trim();
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
- stylesheets[selectorList[j]] = Object.assign(stylesheets[selectorList[j]] || {}, stylesheet.style);
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 = /(-?[\d\.?]+)[,|\s](-?[\d\.?]+)/g;
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 = /(-?[\d\.?]+)[,|\s](-?[\d\.?]+)/g;
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.substr(0, openParPos);
875
- const array = parseFloats(transformText.substr(openParPos + 1, closeParPos - openParPos - 1));
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 = tx;
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 = -array[0] * Math.PI / 180;
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.identity().translate(-cx, -cy);
899
- tempTransform2.identity().rotate(angle);
902
+ tempTransform1.makeTranslation(-cx, -cy);
903
+ tempTransform2.makeRotation(angle);
900
904
  tempTransform3.multiplyMatrices(tempTransform2, tempTransform1);
901
- tempTransform1.identity().translate(cx, cy);
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
- const isRotated = isTransformRotated(m);
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
- curve.xRadius *= getTransformScaleX(m);
970
- curve.yRadius *= getTransformScaleY(m);
1018
+ if (isTransformSkewed(m)) {
1019
+ transfEllipseGeneric(curve);
1020
+ } else {
1021
+ transfEllipseNoSkew(curve);
1022
+ }
971
1023
  }
972
1024
  }
973
1025
  }
974
1026
  }
975
- function isTransformRotated(m) {
976
- return m.elements[1] !== 0 || m.elements[3] !== 0;
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 identifier2 = stack[i2];
1286
+ const identifier = stack[i2];
1186
1287
  if (isHole) {
1187
- lastCWValue = allPaths[identifier2].isCW;
1288
+ lastCWValue = allPaths[identifier].isCW;
1188
1289
  isHole = false;
1189
- isHoleFor = identifier2;
1190
- } else if (lastCWValue !== allPaths[identifier2].isCW) {
1191
- lastCWValue = allPaths[identifier2].isCW;
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: 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(p, simplePaths, scanlineMinX, scanlineMaxX, shapePath.userData.style.fillRule)
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 !== 0) {
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, 1);
1575
- addVertex(currentPointR, u1, 0);
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(nextPointR, u, 0);
1598
- addVertex(innerPoint, u, 0.5);
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
- tempV2_3.toArray(vertices, vl - 2 * 3);
1679
- tempV2_4.toArray(vertices, vl - 1 * 3);
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
  }