x_ite 8.6.5 → 8.6.6

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.
Files changed (56) hide show
  1. package/dist/assets/components/Annotation.js +13 -13
  2. package/dist/assets/components/Annotation.min.js +1 -1
  3. package/dist/assets/components/CADGeometry.js +13 -13
  4. package/dist/assets/components/CADGeometry.min.js +1 -1
  5. package/dist/assets/components/CubeMapTexturing.js +25 -25
  6. package/dist/assets/components/CubeMapTexturing.min.js +1 -1
  7. package/dist/assets/components/DIS.js +13 -13
  8. package/dist/assets/components/DIS.min.js +1 -1
  9. package/dist/assets/components/EventUtilities.js +9 -9
  10. package/dist/assets/components/EventUtilities.min.js +1 -1
  11. package/dist/assets/components/Geometry2D.js +19 -19
  12. package/dist/assets/components/Geometry2D.min.js +1 -1
  13. package/dist/assets/components/Geospatial.js +33 -33
  14. package/dist/assets/components/Geospatial.min.js +1 -1
  15. package/dist/assets/components/HAnim.js +18 -18
  16. package/dist/assets/components/HAnim.min.js +1 -1
  17. package/dist/assets/components/KeyDeviceSensor.js +8 -8
  18. package/dist/assets/components/KeyDeviceSensor.min.js +1 -1
  19. package/dist/assets/components/Layout.js +27 -27
  20. package/dist/assets/components/Layout.min.js +1 -1
  21. package/dist/assets/components/NURBS.js +24 -24
  22. package/dist/assets/components/NURBS.min.js +1 -1
  23. package/dist/assets/components/ParticleSystems.js +23 -23
  24. package/dist/assets/components/ParticleSystems.min.js +1 -1
  25. package/dist/assets/components/Picking.js +19 -19
  26. package/dist/assets/components/Picking.min.js +1 -1
  27. package/dist/assets/components/RigidBodyPhysics.js +18 -18
  28. package/dist/assets/components/RigidBodyPhysics.min.js +1 -1
  29. package/dist/assets/components/Scripting.js +28 -28
  30. package/dist/assets/components/Scripting.min.js +1 -1
  31. package/dist/assets/components/Text.js +24 -24
  32. package/dist/assets/components/Text.min.js +1 -1
  33. package/dist/assets/components/TextureProjector.js +14 -14
  34. package/dist/assets/components/TextureProjector.min.js +1 -1
  35. package/dist/assets/components/Texturing3D.js +30 -30
  36. package/dist/assets/components/Texturing3D.min.js +1 -1
  37. package/dist/assets/components/VolumeRendering.js +19 -19
  38. package/dist/assets/components/VolumeRendering.min.js +1 -1
  39. package/dist/assets/components/X_ITE.js +9 -9
  40. package/dist/assets/components/X_ITE.min.js +1 -1
  41. package/dist/x_ite.css +1 -1
  42. package/dist/x_ite.js +440 -351
  43. package/dist/x_ite.min.js +1 -1
  44. package/dist/x_ite.zip +0 -0
  45. package/docs/_config.yml +1 -1
  46. package/docs/_posts/components/Navigation/NavigationInfo.md +8 -3
  47. package/docs/_posts/laboratory/x3d-file-converter.md +2 -0
  48. package/package.json +1 -1
  49. package/src/x_ite/Base/Events.js +10 -23
  50. package/src/x_ite/Base/X3DObject.js +29 -16
  51. package/src/x_ite/Browser/VERSION.js +1 -1
  52. package/src/x_ite/Components/Shape/Material.js +2 -2
  53. package/src/x_ite/Components/Shape/PhysicalMaterial.js +2 -2
  54. package/src/x_ite/Components/Shape/UnlitMaterial.js +2 -2
  55. package/src/x_ite/Components/Texturing/ImageTexture.js +3 -0
  56. package/src/x_ite/Parser/SVGParser.js +337 -251
@@ -128,13 +128,14 @@ function SVGParser (scene)
128
128
 
129
129
  // Globals
130
130
 
131
- this .viewBox = new Vector4 (0, 0, 100, 100);
132
- this .modelMatrix = new MatrixStack (Matrix4);
133
- this .nodes = new Map ();
134
- this .lineProperties = new Map ();
135
- this .tessy = this .createTesselator ();
136
- this .canvas = document .createElement ("canvas");
137
- this .context = this .canvas .getContext ("2d");
131
+ this .viewBox = new Vector4 (0, 0, 100, 100);
132
+ this .modelMatrix = new MatrixStack (Matrix4);
133
+ this .fillGeometries = new Map ();
134
+ this .strokeGeometries = new Map ();
135
+ this .lineProperties = new Map ();
136
+ this .tessy = this .createTesselator ();
137
+ this .canvas = document .createElement ("canvas");
138
+ this .context = this .canvas .getContext ("2d");
138
139
 
139
140
  this .styles = [{
140
141
  display: "inline",
@@ -366,9 +367,6 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
366
367
  },
367
368
  element: function (xmlElement)
368
369
  {
369
- if (this .used (xmlElement))
370
- return;
371
-
372
370
  switch (xmlElement .nodeName)
373
371
  {
374
372
  case "use":
@@ -397,22 +395,11 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
397
395
  return this .pathElement (xmlElement);
398
396
  }
399
397
  },
400
- used: function (xmlElement)
401
- {
402
- const node = this .nodes .get (xmlElement);
403
-
404
- if (!node)
405
- return false;
406
-
407
- this .groupNodes .at (-1) .children .push (node);
408
-
409
- return true;
410
- },
411
398
  useElement: function (xmlElement)
412
399
  {
413
400
  // Get href.
414
401
 
415
- const usedElement = this .hrefAttribute (xmlElement .getAttribute ("xlink:href"));
402
+ const usedElement = this .hrefAttribute (xmlElement .getAttribute ("href") || xmlElement .getAttribute ("xlink:href"));
416
403
 
417
404
  if (!usedElement)
418
405
  return;
@@ -436,13 +423,7 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
436
423
 
437
424
  this .element (usedElement);
438
425
 
439
- this .groupNodes .pop ();
440
- this .modelMatrix .pop ();
441
- this .styles .pop ();
442
-
443
- // Add node.
444
-
445
- this .groupNodes .at (-1) .children .push (transformNode);
426
+ this .popAll ();
446
427
  },
447
428
  gElement: function (xmlElement)
448
429
  {
@@ -461,13 +442,7 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
461
442
 
462
443
  this .elements (xmlElement);
463
444
 
464
- this .groupNodes .pop ();
465
- this .modelMatrix .pop ();
466
- this .styles .pop ();
467
-
468
- // Add node.
469
-
470
- this .groupNodes .at (-1) .children .push (transformNode);
445
+ this .popAll ();
471
446
  },
472
447
  switchElement: function (xmlElement)
473
448
  {
@@ -492,13 +467,7 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
492
467
 
493
468
  this .elements (xmlElement);
494
469
 
495
- this .groupNodes .pop ();
496
- this .modelMatrix .pop ();
497
- this .styles .pop ();
498
-
499
- // Add node.
500
-
501
- this .groupNodes .at (-1) .children .push (transformNode);
470
+ this .popAll ();
502
471
  },
503
472
  aElement: function (xmlElement)
504
473
  {
@@ -510,8 +479,8 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
510
479
  // Get attributes.
511
480
 
512
481
  const
513
- href = xmlElement .getAttribute ("xlink:href"),
514
- title = xmlElement .getAttribute ("xlink:title"),
482
+ href = xmlElement .getAttribute ("href") || xmlElement .getAttribute ("xlink:href"),
483
+ title = xmlElement .getAttribute ("title") || xmlElement .getAttribute ("xlink:title"),
515
484
  target = xmlElement .getAttribute ("target");
516
485
 
517
486
  // Create Transform node.
@@ -535,11 +504,7 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
535
504
 
536
505
  this .elements (xmlElement);
537
506
 
538
- this .groupNodes .pop ();
539
- this .modelMatrix .pop ();
540
- this .styles .pop ();
541
-
542
- this .groupNodes .at (-1) .children .push (transformNode);
507
+ this .popAll ();
543
508
  },
544
509
  rectElement: function (xmlElement)
545
510
  {
@@ -579,41 +544,60 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
579
544
  {
580
545
  const
581
546
  shapeNode = scene .createNode ("Shape"),
582
- rectangleNode = scene .createNode ("Rectangle2D");
547
+ rectangleNode = this .fillGeometries .get (xmlElement);
583
548
 
549
+ transformNode .children .push (shapeNode);
584
550
  shapeNode .appearance = this .createFillAppearance (bbox);
585
- shapeNode .geometry = rectangleNode;
586
- rectangleNode .solid = this .solid;
587
- rectangleNode .size = size;
588
551
 
589
- transformNode .children .push (shapeNode);
552
+ if (rectangleNode)
553
+ {
554
+ shapeNode .geometry = rectangleNode;
555
+ }
556
+ else
557
+ {
558
+ const rectangleNode = scene .createNode ("Rectangle2D");
559
+
560
+ this .fillGeometries .set (xmlElement, rectangleNode);
561
+
562
+ shapeNode .geometry = rectangleNode;
563
+ rectangleNode .solid = this .solid;
564
+ rectangleNode .size = size;
565
+ }
590
566
  }
591
567
 
592
568
  if (this .style .strokeType !== "none")
593
569
  {
594
570
  const
595
- shapeNode = scene .createNode ("Shape"),
596
- polylineNode = scene .createNode ("Polyline2D"),
597
- width1_2 = width / 2,
598
- height1_2 = height / 2;
571
+ shapeNode = scene .createNode ("Shape"),
572
+ polylineNode = this .strokeGeometries .get (xmlElement);
599
573
 
574
+ transformNode .children .push (shapeNode);
600
575
  shapeNode .appearance = this .createStrokeAppearance ();
601
- shapeNode .geometry = polylineNode;
602
576
 
603
- polylineNode .lineSegments = [ width1_2, height1_2,
604
- -width1_2, height1_2,
605
- -width1_2, -height1_2,
606
- width1_2, -height1_2,
607
- width1_2, height1_2];
577
+ if (polylineNode)
578
+ {
579
+ shapeNode .geometry = polylineNode;
580
+ }
581
+ else
582
+ {
583
+ const
584
+ polylineNode = scene .createNode ("Polyline2D"),
585
+ width1_2 = width / 2,
586
+ height1_2 = height / 2;
587
+
588
+ this .strokeGeometries .set (xmlElement, polylineNode);
608
589
 
609
- transformNode .children .push (shapeNode);
610
- }
590
+ shapeNode .geometry = polylineNode;
611
591
 
612
- this .groupNodes .pop ();
613
- this .modelMatrix .pop ();
614
- this .styles .pop ();
592
+ polylineNode .lineSegments = [ width1_2, height1_2,
593
+ -width1_2, height1_2,
594
+ -width1_2, -height1_2,
595
+ width1_2, -height1_2,
596
+ width1_2, height1_2];
597
+ }
598
+ }
615
599
 
616
- this .groupNodes .at (-1) .children .push (transformNode);
600
+ this .popAll ();
617
601
  }
618
602
  else
619
603
  {
@@ -628,7 +612,7 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
628
612
  const
629
613
  xOffsets = [x + width - rx, x + rx , x + rx, x + width - rx],
630
614
  yOffsets = [y + height - ry, y + height - ry, y + ry, y + ry],
631
- points = Object .assign ([ ], { index: 0, closed: true });
615
+ points = Object .assign ([ ], { closed: true });
632
616
 
633
617
  for (let c = 0; c < 4; ++ c)
634
618
  {
@@ -676,34 +660,52 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
676
660
  {
677
661
  const
678
662
  shapeNode = scene .createNode ("Shape"),
679
- diskNode = scene .createNode ("Disk2D");
663
+ diskNode = this .fillGeometries .get (xmlElement);
680
664
 
665
+ transformNode .children .push (shapeNode);
681
666
  shapeNode .appearance = this .createFillAppearance (bbox);
682
- shapeNode .geometry = diskNode;
683
- diskNode .solid = this .solid;
684
- diskNode .outerRadius = r;
685
667
 
686
- transformNode .children .push (shapeNode);
668
+ if (diskNode)
669
+ {
670
+ shapeNode .geometry = diskNode;
671
+ }
672
+ else
673
+ {
674
+ const diskNode = scene .createNode ("Disk2D");
675
+
676
+ this .fillGeometries .set (xmlElement, diskNode);
677
+
678
+ shapeNode .geometry = diskNode;
679
+ diskNode .solid = this .solid;
680
+ diskNode .outerRadius = r;
681
+ }
687
682
  }
688
683
 
689
684
  if (this .style .strokeType !== "none")
690
685
  {
691
686
  const
692
687
  shapeNode = scene .createNode ("Shape"),
693
- circleNode = scene .createNode ("Circle2D");
688
+ circleNode = this .strokeGeometries .get (xmlElement);
694
689
 
690
+ transformNode .children .push (shapeNode);
695
691
  shapeNode .appearance = this .createStrokeAppearance ();
696
- shapeNode .geometry = circleNode;
697
- circleNode .radius = r;
698
692
 
699
- transformNode .children .push (shapeNode);
700
- }
693
+ if (circleNode)
694
+ {
695
+ shapeNode .geometry = circleNode;
696
+ }
697
+ else
698
+ {
699
+ const circleNode = scene .createNode ("Circle2D");
701
700
 
702
- this .groupNodes .pop ();
703
- this .modelMatrix .pop ();
704
- this .styles .pop ();
701
+ this .strokeGeometries .set (xmlElement, circleNode);
705
702
 
706
- this .groupNodes .at (-1) .children .push (transformNode);
703
+ shapeNode .geometry = circleNode;
704
+ circleNode .radius = r;
705
+ }
706
+ }
707
+
708
+ this .popAll ();
707
709
  },
708
710
  ellipseElement: function (xmlElement)
709
711
  {
@@ -734,34 +736,52 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
734
736
  {
735
737
  const
736
738
  shapeNode = scene .createNode ("Shape"),
737
- diskNode = scene .createNode ("Disk2D");
739
+ diskNode = this .fillGeometries .get (xmlElement);
738
740
 
741
+ transformNode .children .push (shapeNode);
739
742
  shapeNode .appearance = this .createFillAppearance (bbox);
740
- shapeNode .geometry = diskNode;
741
- diskNode .solid = this .solid;
742
- diskNode .outerRadius = rMin;
743
743
 
744
- transformNode .children .push (shapeNode);
744
+ if (diskNode)
745
+ {
746
+ shapeNode .geometry = diskNode;
747
+ }
748
+ else
749
+ {
750
+ const diskNode = scene .createNode ("Disk2D");
751
+
752
+ this .fillGeometries .set (xmlElement, diskNode);
753
+
754
+ shapeNode .geometry = diskNode;
755
+ diskNode .solid = this .solid;
756
+ diskNode .outerRadius = rMin;
757
+ }
745
758
  }
746
759
 
747
760
  if (this .style .strokeType !== "none")
748
761
  {
749
762
  const
750
763
  shapeNode = scene .createNode ("Shape"),
751
- circleNode = scene .createNode ("Circle2D");
764
+ circleNode = this .strokeGeometries .get (xmlElement);
752
765
 
766
+ transformNode .children .push (shapeNode);
753
767
  shapeNode .appearance = this .createStrokeAppearance ();
754
- shapeNode .geometry = circleNode;
755
- circleNode .radius = rMin;
756
768
 
757
- transformNode .children .push (shapeNode);
758
- }
769
+ if (circleNode)
770
+ {
771
+ shapeNode .geometry = circleNode;
772
+ }
773
+ else
774
+ {
775
+ const circleNode = scene .createNode ("Circle2D");
759
776
 
760
- this .groupNodes .pop ();
761
- this .modelMatrix .pop ();
762
- this .styles .pop ();
777
+ this .strokeGeometries .set (xmlElement, circleNode);
763
778
 
764
- this .groupNodes .at (-1) .children .push (transformNode);
779
+ shapeNode .geometry = circleNode;
780
+ circleNode .radius = rMin;
781
+ }
782
+ }
783
+
784
+ this .popAll ();
765
785
  },
766
786
  textElement: function (xmlElement)
767
787
  {
@@ -769,55 +789,61 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
769
789
  },
770
790
  imageElement: function (xmlElement)
771
791
  {
772
- // Determine style.
792
+ const transformNode = this .fillGeometries .get (xmlElement);
773
793
 
774
- if (!this .styleAttributes (xmlElement))
775
- return;
776
-
777
- // Create Transform node.
794
+ if (transformNode)
795
+ {
796
+ this .groupNodes .at (-1) .children .push (transformNode);
797
+ }
798
+ else
799
+ {
800
+ // Determine style.
778
801
 
779
- const
780
- x = this .lengthAttribute (xmlElement .getAttribute ("x"), 0, "width"),
781
- y = this .lengthAttribute (xmlElement .getAttribute ("y"), 0, "height"),
782
- width = this .lengthAttribute (xmlElement .getAttribute ("width"), 0, "width"),
783
- height = this .lengthAttribute (xmlElement .getAttribute ("height"), 0, "height"),
784
- href = xmlElement .getAttribute ("xlink:href");
802
+ if (!this .styleAttributes (xmlElement))
803
+ return;
785
804
 
786
- const
787
- scene = this .getExecutionContext (),
788
- transformNode = this .createTransform (xmlElement, new Vector2 (x + width / 2, y + height / 2), new Vector2 (1, -1));
805
+ // Create Transform node.
789
806
 
790
- this .groupNodes .push (transformNode);
807
+ const
808
+ x = this .lengthAttribute (xmlElement .getAttribute ("x"), 0, "width"),
809
+ y = this .lengthAttribute (xmlElement .getAttribute ("y"), 0, "height"),
810
+ width = this .lengthAttribute (xmlElement .getAttribute ("width"), 0, "width"),
811
+ height = this .lengthAttribute (xmlElement .getAttribute ("height"), 0, "height"),
812
+ href = xmlElement .getAttribute ("href") || xmlElement .getAttribute ("xlink:href");
791
813
 
792
- // Create nodes.
814
+ const
815
+ scene = this .getExecutionContext (),
816
+ transformNode = this .createTransform (xmlElement, new Vector2 (x + width / 2, y + height / 2), new Vector2 (1, -1));
793
817
 
794
- const
795
- shapeNode = scene .createNode ("Shape"),
796
- appearanceNode = scene .createNode ("Appearance"),
797
- textureNode = scene .createNode ("ImageTexture"),
798
- rectangleNode = scene .createNode ("Rectangle2D");
818
+ this .fillGeometries .set (xmlElement, transformNode);
819
+ this .groupNodes .push (transformNode);
799
820
 
800
- shapeNode .appearance = appearanceNode;
801
- shapeNode .geometry = rectangleNode;
802
- appearanceNode .texture = textureNode;
803
- textureNode .url = [href];
804
- textureNode .textureProperties = this .texturePropertiesNode;
805
- rectangleNode .solid = this .solid;
806
- rectangleNode .size = new Vector2 (width, height);
821
+ // Create nodes.
807
822
 
808
- transformNode .children .push (shapeNode);
823
+ const
824
+ shapeNode = scene .createNode ("Shape"),
825
+ appearanceNode = scene .createNode ("Appearance"),
826
+ textureNode = scene .createNode ("ImageTexture"),
827
+ rectangleNode = scene .createNode ("Rectangle2D");
828
+
829
+ shapeNode .appearance = appearanceNode;
830
+ shapeNode .geometry = rectangleNode;
831
+ appearanceNode .texture = textureNode;
832
+ textureNode .url = [href];
833
+ textureNode .textureProperties = this .texturePropertiesNode;
834
+ rectangleNode .solid = this .solid;
835
+ rectangleNode .size = new Vector2 (width, height);
809
836
 
810
- this .groupNodes .pop ();
811
- this .modelMatrix .pop ();
812
- this .styles .pop ();
837
+ transformNode .children .push (shapeNode);
813
838
 
814
- this .groupNodes .at (-1) .children .push (transformNode);
839
+ this .popAll ();
840
+ }
815
841
  },
816
842
  polylineElement: function (xmlElement)
817
843
  {
818
844
  // Get points.
819
845
 
820
- const points = Object .assign ([ ], { index: 0 });
846
+ const points = [ ];
821
847
 
822
848
  if (!this .pointsAttribute (xmlElement .getAttribute ("points"), points))
823
849
  return;
@@ -830,7 +856,7 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
830
856
  {
831
857
  // Get points.
832
858
 
833
- const points = Object .assign ([ ], { index: 0, closed: true });
859
+ const points = Object .assign ([ ], { closed: true });
834
860
 
835
861
  if (!this .pointsAttribute (xmlElement .getAttribute ("points"), points))
836
862
  return;
@@ -859,6 +885,30 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
859
885
  if (!this .styleAttributes (xmlElement))
860
886
  return;
861
887
 
888
+ // Filter consecutive equal points.
889
+
890
+ const EPSILON = 1e-9; // Min point distance.
891
+
892
+ contours = contours .map (function (points)
893
+ {
894
+ if (points .closed)
895
+ {
896
+ return Object .assign (points .filter ((p, i, a) => p .distance (a [(i + 1) % a .length]) > EPSILON),
897
+ {
898
+ closed: true,
899
+ });
900
+ }
901
+ else
902
+ {
903
+ return points .filter ((p, i, a) => !i || p .distance (a [i - 1]) > EPSILON);
904
+ }
905
+ })
906
+ .filter (points => points .length > 2);
907
+
908
+ // Add index property to points.
909
+
910
+ contours .forEach ((points, i, a) => points .index = i ? a [i - 1] .index + a [i - 1] .length : 0);
911
+
862
912
  // Create Transform node.
863
913
 
864
914
  const
@@ -882,51 +932,69 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
882
932
  {
883
933
  const
884
934
  shapeNode = scene .createNode ("Shape"),
885
- geometryNode = scene .createNode ("IndexedTriangleSet");
886
-
887
- shapeNode .appearance = this .createFillAppearance (bbox);
888
- shapeNode .geometry = geometryNode;
889
- geometryNode .solid = this .solid;
890
- geometryNode .index = this .triangulatePolygon (contours, coordinateNode);
891
- geometryNode .texCoord = this .createTextureCoordinate (coordinateNode, bbox);
892
- geometryNode .coord = coordinateNode;
935
+ geometryNode = this .fillGeometries .get (xmlElement);
893
936
 
894
937
  transformNode .children .push (shapeNode);
938
+ shapeNode .appearance = this .createFillAppearance (bbox);
939
+
940
+ if (geometryNode)
941
+ {
942
+ shapeNode .geometry = geometryNode;
943
+ }
944
+ else
945
+ {
946
+ const geometryNode = scene .createNode ("IndexedTriangleSet");
947
+
948
+ this .fillGeometries .set (xmlElement, geometryNode);
949
+
950
+ shapeNode .geometry = geometryNode;
951
+ geometryNode .solid = this .solid;
952
+ geometryNode .index = this .triangulatePolygon (contours, coordinateNode);
953
+ geometryNode .texCoord = this .createTextureCoordinate (coordinateNode, bbox);
954
+ geometryNode .coord = coordinateNode;
955
+ }
895
956
  }
896
957
 
897
958
  if (this .style .strokeType !== "none")
898
959
  {
899
960
  const
900
961
  shapeNode = scene .createNode ("Shape"),
901
- geometryNode = scene .createNode ("IndexedLineSet");
962
+ geometryNode = this .strokeGeometries .get (xmlElement);
902
963
 
903
- shapeNode .appearance = this .createStrokeAppearance ();
904
- shapeNode .geometry = geometryNode;
905
- geometryNode .coord = coordinateNode;
964
+ transformNode .children .push (shapeNode);
965
+ shapeNode .appearance = this .createStrokeAppearance ();
906
966
 
907
- // Create contour indices.
967
+ if (geometryNode)
968
+ {
969
+ shapeNode .geometry = geometryNode;
970
+ }
971
+ else
972
+ {
973
+ const geometryNode = scene .createNode ("IndexedLineSet");
908
974
 
909
- const indices = geometryNode .coordIndex;
975
+ this .strokeGeometries .set (xmlElement, geometryNode);
910
976
 
911
- for (const points of contours)
912
- {
913
- for (const i of points .keys ())
914
- indices .push (points .index + i);
977
+ shapeNode .geometry = geometryNode;
978
+ geometryNode .coord = coordinateNode;
915
979
 
916
- if (points .closed)
917
- indices .push (points .index);
980
+ // Create contour indices.
918
981
 
919
- indices .push (-1);
920
- }
982
+ const indices = geometryNode .coordIndex;
921
983
 
922
- transformNode .children .push (shapeNode);
923
- }
984
+ for (const points of contours)
985
+ {
986
+ for (const i of points .keys ())
987
+ indices .push (points .index + i);
924
988
 
925
- this .groupNodes .pop ();
926
- this .modelMatrix .pop ();
927
- this .styles .pop ();
989
+ if (points .closed)
990
+ indices .push (points .index);
928
991
 
929
- this .groupNodes .at (-1) .children .push (transformNode);
992
+ indices .push (-1);
993
+ }
994
+ }
995
+ }
996
+
997
+ this .popAll ();
930
998
  },
931
999
  linearGradientElementUrl: function (xmlElement, bbox)
932
1000
  {
@@ -943,7 +1011,7 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
943
1011
 
944
1012
  // Attribute xlink:href
945
1013
 
946
- const refElement = this .hrefAttribute (xmlElement .getAttribute ("xlink:href"));
1014
+ const refElement = this .hrefAttribute (xmlElement .getAttribute ("href") || xmlElement .getAttribute ("xlink:href"));
947
1015
 
948
1016
  if (refElement)
949
1017
  this .gradientElement (refElement, bbox, gradient);
@@ -988,7 +1056,7 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
988
1056
  {
989
1057
  // Attribute xlink:href
990
1058
 
991
- const refElement = this .hrefAttribute (xmlElement .getAttribute ("xlink:href"));
1059
+ const refElement = this .hrefAttribute (xmlElement .getAttribute ("href") || xmlElement .getAttribute ("xlink:href"));
992
1060
 
993
1061
  if (refElement)
994
1062
  this .gradientElement (refElement, bbox, gradient);
@@ -1062,41 +1130,37 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
1062
1130
  {
1063
1131
  // Add color stops.
1064
1132
 
1065
- const spreadMatrix = new Matrix3 ();
1066
-
1067
1133
  switch (g .spreadMethod)
1068
1134
  {
1069
1135
  default: // pad
1070
1136
  {
1137
+ g .spreadMatrix .identity ();
1138
+
1071
1139
  for (const [o, c, a] of g .stops)
1072
- gradient .addColorStop (o, this .css (c, a));
1140
+ gradient .addColorStop (o, this .cssColor (c, a));
1073
1141
 
1074
1142
  break;
1075
1143
  }
1076
1144
  case "repeat":
1077
1145
  {
1078
- spreadMatrix .assign (g .spreadMatrix);
1079
-
1080
1146
  for (let i = 0; i < SPREAD; ++ i)
1081
1147
  {
1082
1148
  const s = i / SPREAD;
1083
1149
 
1084
1150
  for (const [o, c, a] of g .stops)
1085
- gradient .addColorStop (s + o / SPREAD, this .css (c, a));
1151
+ gradient .addColorStop (s + o / SPREAD, this .cssColor (c, a));
1086
1152
  }
1087
1153
 
1088
1154
  break;
1089
1155
  }
1090
1156
  case "reflect":
1091
1157
  {
1092
- spreadMatrix .assign (g .spreadMatrix);
1093
-
1094
1158
  for (let i = 0; i < SPREAD; ++ i)
1095
1159
  {
1096
1160
  const s = i / SPREAD;
1097
1161
 
1098
1162
  for (const [o, c, a] of g .stops)
1099
- gradient .addColorStop (s + (i % 2 ? 1 - o : o) / SPREAD, this .css (c, a));
1163
+ gradient .addColorStop (s + (i % 2 ? 1 - o : o) / SPREAD, this .cssColor (c, a));
1100
1164
  }
1101
1165
 
1102
1166
  break;
@@ -1117,7 +1181,7 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
1117
1181
  m .multLeft (new Matrix3 (2, 0, 0, 0, 2, 0, -1, -1, 1));
1118
1182
 
1119
1183
  m .multLeft (g .transform);
1120
- m .multLeft (spreadMatrix);
1184
+ m .multLeft (g .spreadMatrix);
1121
1185
 
1122
1186
  // Paint.
1123
1187
 
@@ -1319,7 +1383,6 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
1319
1383
 
1320
1384
  let
1321
1385
  points = [ ],
1322
- index = 0,
1323
1386
  previous = "",
1324
1387
  command = "",
1325
1388
  relative = false,
@@ -1347,11 +1410,7 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
1347
1410
  // moveto
1348
1411
 
1349
1412
  if (points .length > 2)
1350
- {
1351
- contours .push (Object .assign (points, { index: index, closed: false }));
1352
-
1353
- index += points .length;
1354
- }
1413
+ contours .push (Object .assign (points, { closed: false }));
1355
1414
 
1356
1415
  points = [ ];
1357
1416
 
@@ -1823,9 +1882,7 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
1823
1882
  ax = points [0] .x;
1824
1883
  ay = points [0] .y;
1825
1884
 
1826
- contours .push (Object .assign (points, { index: index, closed: true }));
1827
-
1828
- index += points .length;
1885
+ contours .push (Object .assign (points, { closed: true }));
1829
1886
  }
1830
1887
 
1831
1888
  points = [ ];
@@ -1839,7 +1896,7 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
1839
1896
  }
1840
1897
 
1841
1898
  if (points .length > 2)
1842
- contours .push (Object .assign (points, { index: index, closed: false }));
1899
+ contours .push (Object .assign (points, { closed: false }));
1843
1900
 
1844
1901
  return !! contours .length;
1845
1902
  },
@@ -2077,7 +2134,7 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
2077
2134
  },
2078
2135
  styleAttributes: function (xmlElement)
2079
2136
  {
2080
- const style = Object .assign ({ }, this .styles [0]);
2137
+ const style = Object .assign ({ }, this .styles .at (-1));
2081
2138
 
2082
2139
  if (this .style .display === "none")
2083
2140
  return false;
@@ -2112,6 +2169,9 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
2112
2169
  },
2113
2170
  parseStyle: function (style, value)
2114
2171
  {
2172
+ if (value === "inherit" || value == "unset")
2173
+ return;
2174
+
2115
2175
  this .parseValue (value);
2116
2176
 
2117
2177
  switch (style)
@@ -2153,15 +2213,9 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
2153
2213
  },
2154
2214
  displayStyle: function (value)
2155
2215
  {
2156
- if (value === null)
2157
- return;
2158
-
2159
2216
  if (value === "default")
2160
- return;
2161
-
2162
- if (value === "inherit")
2163
2217
  {
2164
- this .style .display = styles .at (-1) .display;
2218
+ this .style .display = "inline";
2165
2219
  return;
2166
2220
  }
2167
2221
 
@@ -2169,10 +2223,11 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
2169
2223
  },
2170
2224
  fillStyle: function (value)
2171
2225
  {
2172
- if (this .urlValue ())
2226
+ if (value === "default")
2173
2227
  {
2174
- this .style .fillType = "URL";
2175
- this .style .fillURL = this .result [1] .trim ();
2228
+ this .style .fillType = this .styles [0] .fillType;
2229
+ this .style .fillColor = this .styles [0] .fillColor;
2230
+ this .style .fillURL = this .styles [0] .fillURL;
2176
2231
  return;
2177
2232
  }
2178
2233
 
@@ -2188,27 +2243,25 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
2188
2243
  return;
2189
2244
  }
2190
2245
 
2191
- if (!value .match (/^(?:inherit|unset|default)$/))
2246
+ if (this .urlValue ())
2192
2247
  {
2193
- if (this .colorValue (this .styles .at (-1) .fillColor))
2194
- {
2195
- this .style .fillType = "COLOR";
2196
- this .style .fillColor = this .value .copy ();
2197
- return;
2198
- }
2248
+ this .style .fillType = "URL";
2249
+ this .style .fillURL = this .result [1] .trim ();
2250
+ return;
2199
2251
  }
2200
2252
 
2201
- // inherit
2202
-
2203
- this .style .fillType = this .styles .at (-1) .fillType;
2204
- this .style .fillColor = this .styles .at (-1) .fillColor;
2205
- this .style .fillURL = this .styles .at (-1) .fillURL;
2253
+ if (this .colorValue (this .styles .at (-1) .fillColor))
2254
+ {
2255
+ this .style .fillType = "COLOR";
2256
+ this .style .fillColor = this .value .copy ();
2257
+ return;
2258
+ }
2206
2259
  },
2207
2260
  fillOpacityStyle: function (value)
2208
2261
  {
2209
- if (this .double ())
2262
+ if (value === "default")
2210
2263
  {
2211
- this .style .fillOpacity = Algorithm .clamp (this .value, 0, 1);
2264
+ this .style .fillOpacity = this .styles [0] .fillOpacity;
2212
2265
  return;
2213
2266
  }
2214
2267
 
@@ -2218,20 +2271,29 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
2218
2271
  return;
2219
2272
  }
2220
2273
 
2221
- // inherit
2222
-
2223
- this .style .fillOpacity = this .styles .at (-1) .fillOpacity;
2274
+ if (this .double ())
2275
+ {
2276
+ this .style .fillOpacity = Algorithm .clamp (this .value, 0, 1);
2277
+ return;
2278
+ }
2224
2279
  },
2225
2280
  fillRuleStyle: function (value)
2226
2281
  {
2282
+ if (value === "default")
2283
+ {
2284
+ this .style .fillRule = this .styles [0] .fillRule;
2285
+ return;
2286
+ }
2287
+
2227
2288
  this .style .fillRule = value;
2228
2289
  },
2229
2290
  strokeStyle: function (value)
2230
2291
  {
2231
- if (this .urlValue ())
2292
+ if (value === "default")
2232
2293
  {
2233
- this .style .strokeType = "URL";
2234
- this .style .strokeURL = this .result [1] .trim ();
2294
+ this .style .strokeType = this .styles [0] .strokeType;
2295
+ this .style .strokeColor = this .styles [0] .strokeColor;
2296
+ this .style .strokeURL = this .styles [0] .strokeURL;
2235
2297
  return;
2236
2298
  }
2237
2299
 
@@ -2247,27 +2309,25 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
2247
2309
  return;
2248
2310
  }
2249
2311
 
2250
- if (!value .match (/^(?:inherit|unset|default)$/))
2312
+ if (this .urlValue ())
2251
2313
  {
2252
- if (this .colorValue (this .styles .at (-1) .strokeColor))
2253
- {
2254
- this .style .strokeType = "COLOR";
2255
- this .style .strokeColor = this .value .copy ();
2256
- return;
2257
- }
2314
+ this .style .strokeType = "URL";
2315
+ this .style .strokeURL = this .result [1] .trim ();
2316
+ return;
2258
2317
  }
2259
2318
 
2260
- // inherit
2261
-
2262
- this .style .strokeType = this .styles .at (-1) .strokeType;
2263
- this .style .strokeColor = this .styles .at (-1) .strokeColor;
2264
- this .style .strokeURL = this .styles .at (-1) .strokeURL;
2319
+ if (this .colorValue (this .styles .at (-1) .strokeColor))
2320
+ {
2321
+ this .style .strokeType = "COLOR";
2322
+ this .style .strokeColor = this .value .copy ();
2323
+ return;
2324
+ }
2265
2325
  },
2266
2326
  strokeOpacityStyle: function (value)
2267
2327
  {
2268
- if (this .double ())
2328
+ if (value === "default")
2269
2329
  {
2270
- this .style .strokeOpacity = Algorithm .clamp (this .value, 0, 1);
2330
+ this .style .strokeOpacity = this .styles [0] .strokeOpacity;
2271
2331
  return;
2272
2332
  }
2273
2333
 
@@ -2277,15 +2337,17 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
2277
2337
  return;
2278
2338
  }
2279
2339
 
2280
- // inherit
2281
-
2282
- this .style .strokeOpacity = this .styles .at (-1) .strokeOpacity;
2340
+ if (this .double ())
2341
+ {
2342
+ this .style .strokeOpacity = Algorithm .clamp (this .value, 0, 1);
2343
+ return;
2344
+ }
2283
2345
  },
2284
2346
  strokeWidthStyle: function (value)
2285
2347
  {
2286
- if (this .double ())
2348
+ if (value === "default")
2287
2349
  {
2288
- this .style .strokeWidth = this .lengthAttribute (this .value, 1);
2350
+ this .style .strokeWidth = this .styles [0] .strokeWidth;
2289
2351
  return;
2290
2352
  }
2291
2353
 
@@ -2295,15 +2357,17 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
2295
2357
  return;
2296
2358
  }
2297
2359
 
2298
- // inherit
2299
-
2300
- this .style .strokeWidth = this .styles .at (-1) .strokeWidth;
2360
+ if (this .double ())
2361
+ {
2362
+ this .style .strokeWidth = this .lengthAttribute (this .value, 1);
2363
+ return;
2364
+ }
2301
2365
  },
2302
2366
  opacityStyle: function (value)
2303
2367
  {
2304
- if (this .double ())
2368
+ if (value === "default")
2305
2369
  {
2306
- this .style .opacity = Algorithm .clamp (this .value, 0, 1) * this .styles .at (-1) .opacity;
2370
+ this .style .opacity = this .styles [0] .opacity;
2307
2371
  return;
2308
2372
  }
2309
2373
 
@@ -2312,9 +2376,21 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
2312
2376
  this .style .opacity = 0;
2313
2377
  return;
2314
2378
  }
2379
+
2380
+ if (this .double ())
2381
+ {
2382
+ this .style .opacity = Algorithm .clamp (this .value, 0, 1) * this .styles .at (-1) .opacity;
2383
+ return;
2384
+ }
2315
2385
  },
2316
2386
  stopColorStyle: function (value)
2317
2387
  {
2388
+ if (value === "default")
2389
+ {
2390
+ this .style .stopColor = this .styles [0] .stopColor;
2391
+ return;
2392
+ }
2393
+
2318
2394
  if (this .colorValue (Color4 .Black))
2319
2395
  {
2320
2396
  this .style .stopColor = this .value .copy ();
@@ -2323,9 +2399,9 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
2323
2399
  },
2324
2400
  stopOpacityStyle: function (value)
2325
2401
  {
2326
- if (this .double ())
2402
+ if (value === "default")
2327
2403
  {
2328
- this .style .stopOpacity = Algorithm .clamp (this .value, 0, 1);
2404
+ this .style .stopOpacity = this .styles [0] .stopOpacity;
2329
2405
  return;
2330
2406
  }
2331
2407
 
@@ -2334,18 +2410,22 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
2334
2410
  this .style .stopOpacity = 0;
2335
2411
  return;
2336
2412
  }
2413
+
2414
+ if (this .double ())
2415
+ {
2416
+ this .style .stopOpacity = Algorithm .clamp (this .value, 0, 1);
2417
+ return;
2418
+ }
2337
2419
  },
2338
2420
  vectorEffectStyle: function (value)
2339
2421
  {
2340
- if (value !== "inherit")
2422
+ if (value === "default")
2341
2423
  {
2342
- this .style .vectorEffect = value;
2424
+ this .style .vectorEffect = this .styles [0] .vectorEffect;
2343
2425
  return;
2344
2426
  }
2345
2427
 
2346
- // inherit
2347
-
2348
- this .style .vectorEffect = this .styles .at (-1) .vectorEffect;
2428
+ this .style .vectorEffect = value;
2349
2429
  },
2350
2430
  parseValue: function (value)
2351
2431
  {
@@ -2406,7 +2486,7 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
2406
2486
  if (!Grammar .color .parse (this))
2407
2487
  return false;
2408
2488
 
2409
- const defaultColor = this .css (c);
2489
+ const defaultColor = this .cssColor (c);
2410
2490
 
2411
2491
  this .value = color .set (... this .convertColor (this .result [1], defaultColor));
2412
2492
 
@@ -2417,7 +2497,7 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
2417
2497
  {
2418
2498
  return Grammar .url .parse (this);
2419
2499
  },
2420
- css: function (c, a = c .a)
2500
+ cssColor: function (c, a = c .a)
2421
2501
  {
2422
2502
  return `rgba(${c .r * 255},${c .g * 255},${c .b * 255},${a})`;
2423
2503
  },
@@ -2456,12 +2536,18 @@ SVGParser .prototype = Object .assign (Object .create (X3DParser .prototype),
2456
2536
 
2457
2537
  this .idAttribute (xmlElement .getAttribute ("id"), transformNode);
2458
2538
 
2459
- // Nodes
2539
+ // Add node to parent.
2460
2540
 
2461
- this .nodes .set (xmlElement, transformNode);
2541
+ this .groupNodes .at (-1) .children .push (transformNode);
2462
2542
 
2463
2543
  return transformNode;
2464
2544
  },
2545
+ popAll: function ()
2546
+ {
2547
+ this .groupNodes .pop ();
2548
+ this .modelMatrix .pop ();
2549
+ this .styles .pop ();
2550
+ },
2465
2551
  createFillAppearance: function (bbox)
2466
2552
  {
2467
2553
  const