Forráskód Böngészése

Removed PlPlot in favour of Plotly.Sharp

Vicente Penades 5 éve
szülő
commit
43fe29a858

+ 7 - 0
SharpGLTF.sln

@@ -43,6 +43,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharpGLTF.Core.Tests", "tes
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SharpGLTF.Toolkit.Tests", "tests\SharpGLTF.Toolkit.Tests\SharpGLTF.Toolkit.Tests.csproj", "{7FEFC259-51D6-4409-8724-8DE0EA8D5CD9}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpGLTF.Plotly", "examples\SharpGLTF.Plotly\SharpGLTF.Plotly.csproj", "{A63C2A2D-950F-4C76-9299-2B2D325A8653}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -97,6 +99,10 @@ Global
 		{7FEFC259-51D6-4409-8724-8DE0EA8D5CD9}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{7FEFC259-51D6-4409-8724-8DE0EA8D5CD9}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{7FEFC259-51D6-4409-8724-8DE0EA8D5CD9}.Release|Any CPU.Build.0 = Release|Any CPU
+		{A63C2A2D-950F-4C76-9299-2B2D325A8653}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{A63C2A2D-950F-4C76-9299-2B2D325A8653}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{A63C2A2D-950F-4C76-9299-2B2D325A8653}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{A63C2A2D-950F-4C76-9299-2B2D325A8653}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -114,6 +120,7 @@ Global
 		{7A5EAF7E-D6A6-4861-9488-F98E4AA00A3A} = {0CBF510D-D836-40BA-95EC-E93FDBB90632}
 		{56FE769E-6B09-462B-9947-A9B64161CD80} = {0CBF510D-D836-40BA-95EC-E93FDBB90632}
 		{7FEFC259-51D6-4409-8724-8DE0EA8D5CD9} = {0CBF510D-D836-40BA-95EC-E93FDBB90632}
+		{A63C2A2D-950F-4C76-9299-2B2D325A8653} = {83E7E49D-8A28-45E8-9DBD-1F3AEDEF3E42}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {1D7BBAD9-834C-4981-AC96-0AA5226FC43F}

+ 1 - 1
build/SharpGLTF.CodeGen/SharpGLTF.CodeGen.csproj

@@ -8,7 +8,7 @@
 
   <ItemGroup>
     <PackageReference Include="LibGit2Sharp" Version="0.26.2" />    
-    <PackageReference Include="NJsonSchema.CodeGeneration.CSharp" Version="10.1.21" />
+    <PackageReference Include="NJsonSchema.CodeGeneration.CSharp" Version="10.1.23" />
   </ItemGroup>
 
 </Project>

+ 63 - 0
examples/SharpGLTF.Plotly/Extensions.cs

@@ -0,0 +1,63 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Numerics;
+using System.Transactions;
+
+using SharpGLTF.Geometry;
+using SharpGLTF.Materials;
+using SharpGLTF.Schema2;
+
+namespace SharpGLTF
+{
+    public static class PlotlyExtensions
+    {
+        public static Plotly.Box<Plotly.Types.ITracesProperty> ToTrace(this Schema2.Scene scene)
+        {
+            return PlotlyFactory.ToTrace(scene.EvaluateTriangles(), GetMaterialColor);
+        }
+
+        public static Plotly.Box<Plotly.Types.ITracesProperty> ToTrace(this Schema2.Mesh mesh)
+        {
+            return PlotlyFactory.ToTrace(mesh.EvaluateTriangles(), GetMaterialColor);
+        }
+        
+        public static Plotly.Box<Plotly.Types.ITracesProperty> ToTrace(this IMeshBuilder<MaterialBuilder> mesh)
+        {
+            IEnumerable<(IVertexBuilder, IVertexBuilder, IVertexBuilder, MaterialBuilder)> _enumTris()
+            {
+                foreach (var p in mesh.Primitives)
+                {
+                    foreach (var (A, B, C) in p.Triangles)
+                    {
+                        var va = p.Vertices[A];
+                        var vb = p.Vertices[B];
+                        var vc = p.Vertices[C];
+
+                        yield return (va, vb, vc, p.Material);
+                    }
+                }
+            }
+
+            return PlotlyFactory.ToTrace(_enumTris(), GetMaterialColor);
+        }
+
+        private static int GetMaterialColor(Schema2.Material material)
+        {
+            var mb = new MaterialBuilder();
+            material.CopyTo(mb);
+            return GetMaterialColor(mb);
+        }
+
+        private static int GetMaterialColor(MaterialBuilder material)
+        {
+            var color = (material.GetChannel(KnownChannel.BaseColor) ?? material.GetChannel(KnownChannel.Diffuse))?.Parameter ?? Vector4.One * 0.8f;
+
+            color *= 255;
+
+            var ccc = color.X * 65536 + color.Y * 256 + color.Z;
+
+            return (int)ccc;
+        }
+    }
+}

+ 70 - 0
examples/SharpGLTF.Plotly/PlotlyFactory.cs

@@ -0,0 +1,70 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Numerics;
+using System.Text;
+
+using Plotly;
+using Plotly.Types;
+
+using SharpGLTF.Geometry;
+
+namespace SharpGLTF
+{
+    static class PlotlyFactory
+    {
+        public static Box<ITracesProperty> ToTrace<TMaterial>(IEnumerable<(IVertexBuilder A, IVertexBuilder B, IVertexBuilder C, TMaterial Material)> tris, Func<TMaterial, int> materialColorFunc)
+        {
+            var mats = new Dictionary<TMaterial, int>();                // materials to color mapping
+
+            var vrts = new List<(Vector3 p, Vector3 n)>();              // vertex list
+            var vrtm = new Dictionary<(Vector3 p, Vector3 n), int>();   // vertex sharing map
+
+            var idxs = new List<(int, int, int)>();                     // triangle indices
+            var tric = new List<int>();                                 // face colors
+
+            int _useSharedVertex(IVertexBuilder v)
+            {
+                var g = v.GetGeometry();
+
+                g.TryGetNormal(out Vector3 n);
+                var item = (g.GetPosition(), n);
+                if (vrtm.TryGetValue(item, out int idx)) return idx;
+                idx = vrts.Count;
+                vrts.Add(item);
+                vrtm.Add(item, idx);
+                return idx;
+            }
+
+            foreach (var (A, B, C, Material) in tris)
+            {
+                if (!mats.TryGetValue(Material, out int color))
+                {
+                    mats[Material] = color = materialColorFunc(Material);
+                }
+
+                var ap = _useSharedVertex(A);
+                var bp = _useSharedVertex(B);
+                var cp = _useSharedVertex(C);
+
+                idxs.Add((ap, bp, cp));
+                tric.Add(color);
+            }
+
+            // create a Plotly Mesh3D from the previously filled lists.
+
+            var mx = Mesh3d.x(vrts.Select(item => item.p.X));
+            var my = Mesh3d.y(vrts.Select(item => item.p.Y));
+            var mz = Mesh3d.z(vrts.Select(item => item.p.Z));
+
+            var mi = Mesh3d.i(idxs.Select(item => item.Item1).ToArray());
+            var mj = Mesh3d.j(idxs.Select(item => item.Item2).ToArray());
+            var mk = Mesh3d.k(idxs.Select(item => item.Item3).ToArray());
+
+            var mo = Mesh3d.opacity(1);
+            var mc = Mesh3d.facecolor(tric.ToArray());
+
+            return Traces.mesh3d(mx, my, mz, mi, mj, mk, mo, mc);
+        }
+    }
+}

+ 15 - 0
examples/SharpGLTF.Plotly/SharpGLTF.Plotly.csproj

@@ -0,0 +1,15 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>netstandard2.0</TargetFramework>
+  </PropertyGroup>
+
+  <ItemGroup>    
+    <PackageReference Include="Plotly.Sharp" Version="0.0.8196" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\..\src\SharpGLTF.Toolkit\SharpGLTF.Toolkit.csproj" />
+  </ItemGroup>
+
+</Project>

+ 30 - 0
tests/SharpGLTF.NUnit/NUnitGltfUtils.cs

@@ -75,6 +75,36 @@ namespace SharpGLTF
                 fileName = fileName.Replace(" ", "_");
                 Schema2.Schema2Toolkit.SaveAsWavefront(model, fileName);
             }
+            else if (fileName.ToLower().EndsWith(".plotly"))
+            {
+                fileName = fileName.Replace(".plotly", ".html");
+
+                
+
+                var trace = model.DefaultScene.ToTrace();
+                var plot = Plotly.Plot.traces(trace);
+
+                var xaxis = Plotly.Scene.xaxis(Plotly.Xaxis.color("red"));
+                var yaxis = Plotly.Scene.yaxis(Plotly.Yaxis.color("green"));
+                var zaxis = Plotly.Scene.zaxis(Plotly.Zaxis.color("blue"));
+                var camera = Plotly.Camera.up(Plotly.Up.x(0), Plotly.Up.y(1), Plotly.Up.z(0));
+                var scene = Plotly.Layout.scene(Plotly.Scene.Aspectmode.data(), Plotly.Scene.camera(camera) ,xaxis,yaxis,zaxis );
+
+                var layout = Plotly.Plot.layout
+                    ( Plotly.Layout.autosize(true)
+                    // , Plotly.Layout.width(0)
+                    , Plotly.Layout.height(920)
+                    // , Plotly.Layout.margin(Plotly.Margin.autoexpand(true))
+                    // , Plotly.Layout.margin(Plotly.Margin.pad(5))                    
+                    // , Plotly.Layout.margin(Plotly.Margin.t(5), Plotly.Margin.b(5))                    
+                    , scene
+                    );                
+
+                var document = new Plotly.Plot(plot, layout);                
+                var render = document.Render().ToString();
+
+                System.IO.File.WriteAllText(fileName, render);
+            }
 
             // Attach the saved file to the current test
             TestContext.AddTestAttachment(fileName);

+ 11 - 0
tests/SharpGLTF.NUnit/NUnitUtils.cs

@@ -75,5 +75,16 @@ namespace SharpGLTF
 
             return fileName;
         }
+
+        public static T AttachToCurrentTest<T>(this T target, string fileName, Action<T, string> onSave)
+        {
+            var filePath = TestContext.CurrentContext.GetAttachmentPath(fileName, true);
+
+            onSave(target, filePath);
+
+            if (System.IO.File.Exists(filePath)) TestContext.AddTestAttachment(filePath);
+
+            return target;
+        }
     }
 }

+ 54 - 107
tests/SharpGLTF.NUnit/Plotting.cs

@@ -8,13 +8,13 @@ namespace SharpGLTF
 {
     public static class Plotting
     {
-        public static Point2Series ToPointSeries(this IEnumerable<Single> points) { return Point2Series.Create(points); }
+        public static Point2Series ToPointSeries(this IEnumerable<Single> points, string name = null) { return Point2Series.Create(points).WithName(name); }
 
-        public static Point2Series ToPointSeries(this IEnumerable<Double> points) { return Point2Series.Create(points); }
+        public static Point2Series ToPointSeries(this IEnumerable<Double> points, string name = null) { return Point2Series.Create(points).WithName(name); }
 
-        public static Point2Series ToPointSeries(this IEnumerable<Vector2> points) { return Point2Series.Create(points); }
+        public static Point2Series ToPointSeries(this IEnumerable<Vector2> points, string name = null) { return Point2Series.Create(points).WithName(name); }
 
-        public static Point2Series ToLineSeries(this IEnumerable<Vector2> points) { return Point2Series.Create(points, LineType.Continuous); }
+        public static Point2Series ToLineSeries(this IEnumerable<Vector2> points, string name = null) { return Point2Series.Create(points, LineType.Continuous).WithName(name); }
 
         public enum LineType
         {
@@ -89,6 +89,8 @@ namespace SharpGLTF
                 return ps;
             }
 
+            public Point2Series WithName(string name) { Name = name; return this; }
+
             #endregion
 
             #region data
@@ -99,19 +101,33 @@ namespace SharpGLTF
 
             #region properties
 
+            public string Name { get; set; }
+
             public LineType LineType { get; set; }
 
             #endregion
 
             #region API
 
-            public Point2Series WithLineType(LineType t) { LineType = t; return this; }
+            public Point2Series WithLineType(LineType t) { LineType = t; return this; }            
 
             public void DrawToFile(string filePath)
             {
                 DrawToFile(filePath, this);
             }
 
+            private Plotly.Box<Plotly.Types.ITracesProperty> GetTrace()
+            {
+                var x = Plotly.Scatter.x(_Points.Select(item => (float)item.X));
+                var y = Plotly.Scatter.y(_Points.Select(item => (float)item.Y));
+
+                var mode = LineType == LineType.Continuous ? Plotly.Scatter.Mode.lines() : Plotly.Scatter.Mode.markers();
+
+                var name = Plotly.Scatter.name(this.Name);
+
+                return Plotly.Traces.scatter(x, y, mode, name);
+            }
+
             public static (Point2, Point2) GetBounds(params Point2Series[] series)
             {
                 var xmin = series.SelectMany(item => item._Points).Min(item => item.X);
@@ -127,51 +143,18 @@ namespace SharpGLTF
 
             public static void DrawToFile(string filePath, params Point2Series[] series)
             {
-                // arguments check
-                if (string.IsNullOrWhiteSpace(filePath)) throw new ArgumentNullException(nameof(filePath));
-
-                var bounds = GetBounds(series);
-
-                try
-                {
-                    using (var pl = new PLplot.PLStream())
-                    {
-                        pl.sdev("pngcairo");
-                        pl.sfnam(filePath);
-                        pl.spal0("cmap0_alternate.pal");
-
-                        pl.init();
-
-                        pl.env(bounds.Item1.X, bounds.Item2.X, bounds.Item1.Y, bounds.Item2.Y, PLplot.AxesScale.Independent, PLplot.AxisBox.BoxTicksLabelsAxes);
-
-                        for (int i = 0; i < series.Length; ++i)
-                        {
-                            var ps = series[i];
-                            var s = ps._Points;
-
-                            var seriesX = new double[s.Count];
-                            var seriesY = new double[s.Count];
-
-                            for (int j = 0; j < s.Count; ++j)
-                            {
-                                seriesX[j] = s[j].X;
-                                seriesY[j] = s[j].Y;
-                            }
-
-                            pl.col0(i + 2);
-
-                            if (ps.LineType == LineType.Continuous) pl.line(seriesX, seriesY);
-                            else pl.poin(seriesX, seriesY, (char)ps.LineType);
-                        }
-
-                        pl.eop(); // write to disk
-                    }
-                }
-                catch
-                {
-                    NUnit.Framework.TestContext.WriteLine("PLPlot not supported.");
-                }
-            }
+                var traces = series
+                    .Select(item => item.GetTrace())
+                    .ToArray();
+
+                var plot = Plotly.Plot.traces(traces);
+
+                var chart = new Plotly.Plot(plot);
+
+                var html = chart.Render().ToString();
+
+                System.IO.File.WriteAllText(filePath, html);
+            }            
 
             #endregion
         }
@@ -200,12 +183,7 @@ namespace SharpGLTF
             #endregion
 
             #region API
-
-            public void DrawToFile(string filePath)
-            {
-                DrawToFile(filePath, this);
-            }
-
+            
             public static (Vector3 Min,  Vector3 Max) GetBounds(params Point3Series[] series)
             {
                 var xmin = series.SelectMany(item => item._Points).Min(item => item.X);
@@ -223,65 +201,34 @@ namespace SharpGLTF
                 return (new Vector3(xmin, ymin,zmin), new Vector3(xmax, ymax, zmax));
             }
 
-            public static void DrawToFile(string filePath, params Point3Series[] series)
+            private Plotly.Box<Plotly.Types.ITracesProperty> GetTrace()
             {
-                // arguments check
-                if (string.IsNullOrWhiteSpace(filePath)) throw new ArgumentNullException(nameof(filePath));
-
-                var plen = series
-                    .Select(item => item._Points.Count)
-                    .Max();
-
-                if (plen < 1) throw new ArgumentOutOfRangeException($"The series only has {plen} values", nameof(series));
-
-                if (series.Any(item => item._Lines))
-                {
-                    plen = series
-                        .Where(item => item._Lines)
-                        .Select(item => item._Points.Count)
-                        .Max();
-
-                    if (plen < 2) throw new ArgumentOutOfRangeException($"The series only has {plen} values", nameof(series));
-                }
-
-                var bounds = GetBounds(series);
-
-                using (var pl = new PLplot.PLStream())
-                {
-                    pl.sdev("pngcairo");
-                    pl.sfnam(filePath);
-                    pl.spal0("cmap0_alternate.pal");
-
-                    pl.init();
-
-                    pl.env(bounds.Min.X, bounds.Max.X, bounds.Min.Y, bounds.Max.Y, PLplot.AxesScale.Independent, PLplot.AxisBox.BoxTicksLabelsAxes);
+                var x = Plotly.Scatter3d.x(_Points.Select(item => (float)item.X));
+                var y = Plotly.Scatter3d.y(_Points.Select(item => (float)item.Y));
+                var z = Plotly.Scatter3d.z(_Points.Select(item => (float)item.Z));
+                return Plotly.Traces.scatter3d(x, y, z);
+            }
 
-                    for (int i = 0; i < series.Length; ++i)
-                    {
-                        var ps = series[i];
-                        var s = ps._Points;
+            public void DrawToFile(string filePath)
+            {
+                DrawToFile(filePath, this);
+            }
 
-                        var seriesX = new double[s.Count];
-                        var seriesY = new double[s.Count];
-                        var seriesZ = new double[s.Count];
+            public static void DrawToFile(string filePath, params Point3Series[] series)
+            {
+                var traces = series
+                    .Select(item => item.GetTrace())
+                    .ToArray();
 
-                        for (int j = 0; j < s.Count; ++i)
-                        {
-                            seriesX[j] = s[j].X;
-                            seriesY[j] = s[j].Y;
-                            seriesZ[j] = s[j].Z;
-                        }
+                var plot = Plotly.Plot.traces(traces);
 
-                        pl.col0(i + 2);
+                var chart = new Plotly.Plot(plot);
 
-                        if (ps._Lines) pl.line3(seriesX, seriesY, seriesZ);
-                        else pl.poin3(seriesX, seriesY, seriesZ, ps._PointGlyph);
-                    }
+                var html = chart.Render().ToString();
 
-                    pl.eop(); // write to disk
-                }
+                System.IO.File.WriteAllText(filePath, html);
             }
-
+            
             #endregion
         }
     }

+ 3 - 3
tests/SharpGLTF.NUnit/SharpGLTF.NUnit.csproj

@@ -16,13 +16,13 @@
     </Content>
   </ItemGroup>
 
-  <ItemGroup>    
-    <PackageReference Include="nunit" Version="3.12.0" />    
-    <PackageReference Include="PLplot" Version="5.13.7" />
+  <ItemGroup>
+    <PackageReference Include="nunit" Version="3.12.0" />
     <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
   </ItemGroup>
 
   <ItemGroup>    
+    <ProjectReference Include="..\..\examples\SharpGLTF.Plotly\SharpGLTF.Plotly.csproj" />    
     <ProjectReference Include="..\..\src\SharpGLTF.Toolkit\SharpGLTF.Toolkit.csproj" />
   </ItemGroup>
 

+ 17 - 17
tests/SharpGLTF.Tests/Animations/AnimationSamplingTests.cs

@@ -118,14 +118,14 @@ namespace SharpGLTF
 
             for (float amount = 0; amount <= 1; amount += 0.01f)
             {
-                var hermite = Animations.SamplerFactory.CreateHermitePointWeights(amount);
+                var (startPosition, endPosition, startTangent, endTangent) = Animations.SamplerFactory.CreateHermitePointWeights(amount);
 
                 var p = Vector2.Zero;
 
-                p += p1 * hermite.StartPosition;
-                p += p4 * hermite.EndPosition;
-                p += (p2 - p1) * 4 * hermite.StartTangent;
-                p += (p4 - p3) * 4 * hermite.EndTangent;
+                p += p1 * startPosition;
+                p += p4 * endPosition;
+                p += (p2 - p1) * 4 * startTangent;
+                p += (p4 - p3) * 4 * endTangent;
 
                 ppp.Add(p);
             }
@@ -142,11 +142,11 @@ namespace SharpGLTF
 
             // plotting
 
-            var series1 = ppp.ToPointSeries();
-            var series2 = new[] { p1, p2, p3, p4 }.ToLineSeries();
-            var series3 = new[] { pp, pp + pt }.ToLineSeries();
+            var series1 = ppp.ToPointSeries("sampling");
+            var series2 = new[] { p1, p2, p3, p4 }.ToLineSeries("source");
+            var series3 = new[] { pp, pp + pt }.ToLineSeries("tangent");
 
-            new[] { series1, series2, series3 }.AttachToCurrentTest("plot.png");
+            new[] { series1, series2, series3 }.AttachToCurrentTest("plot.html");
         }
 
         [Test]
@@ -160,21 +160,21 @@ namespace SharpGLTF
 
             for (float amount = 0; amount <= 1; amount += 0.1f)
             {
-                var hermite = Animations.SamplerFactory.CreateHermitePointWeights(amount);
+                var (startPosition, endPosition, startTangent, endTangent) = Animations.SamplerFactory.CreateHermitePointWeights(amount);
 
                 var p = Vector2.Zero;
 
-                p += p1 * hermite.StartPosition;
-                p += p2 * hermite.EndPosition;
-                p += t * hermite.StartTangent;
-                p += t * hermite.EndTangent;
+                p += p1 * startPosition;
+                p += p2 * endPosition;
+                p += t * startTangent;
+                p += t * endTangent;
 
                 ppp.Add(p);
             }
 
             var series1 = ppp.ToPointSeries().WithLineType(Plotting.LineType.Star);
 
-            new[] { series1 }.AttachToCurrentTest("plot.png");
+            new[] { series1 }.AttachToCurrentTest("plot.html");
         }
 
         [Test]
@@ -224,7 +224,7 @@ namespace SharpGLTF
 
             angles.ToPointSeries()
                 .WithLineType(Plotting.LineType.Continuous)
-                .AttachToCurrentTest("plot.png");
+                .AttachToCurrentTest("plot.html");
         
         }
 
@@ -261,7 +261,7 @@ namespace SharpGLTF
             points
                 .Select(p => new Vector2(p.X, p.Y))
                 .ToPointSeries()                
-                .AttachToCurrentTest("plot.png");            
+                .AttachToCurrentTest("plot.html");            
         }
 
         [Test]

+ 4 - 0
tests/SharpGLTF.Toolkit.Tests/Geometry/MeshBuilderAdvancedTests.cs

@@ -51,6 +51,7 @@ namespace SharpGLTF.Geometry
 
             scene.AttachToCurrentTest("result.glb");
             scene.AttachToCurrentTest("result.gltf");
+            scene.AttachToCurrentTest("result.plotly");
         }
 
         [Test(Description = "Creates a scene with 4 meshes, where the meshes have been initialized so they can share the same vertex and index buffers")]
@@ -115,6 +116,7 @@ namespace SharpGLTF.Geometry
 
             model.AttachToCurrentTest("result.glb");
             model.AttachToCurrentTest("result.gltf");
+            scene.AttachToCurrentTest("result.plotly");
         }
 
         [Test(Description = "Creates a node animated scene.")]
@@ -283,6 +285,7 @@ namespace SharpGLTF.Geometry
 
             // save the model as GLB
             model.AttachToCurrentTest("terrain.glb");
+            model.AttachToCurrentTest("result.plotly");
         }
 
         [Test(Description = "Creates a scene with 1 million points cloud.")]        
@@ -376,6 +379,7 @@ namespace SharpGLTF.Geometry
             // save the model as GLB
             scene.AttachToCurrentTest("cubes.glb");
             scene.AttachToCurrentTest("cubes.gltf");
+            scene.AttachToCurrentTest("cubes.plotly");
         }
 
         [Test(Description ="Simulates animating mesh visibility by setting scale to (0,0,0)")]

+ 6 - 2
tests/SharpGLTF.Toolkit.Tests/Scenes/SceneBuilderTests.cs

@@ -37,6 +37,7 @@ namespace SharpGLTF.Scenes
 
             scene.AttachToCurrentTest("cube.glb");
             scene.AttachToCurrentTest("cube.gltf");
+            scene.AttachToCurrentTest("cube.plotly");
         }
 
         [Test(Description ="Creates a cube attached to an animated node.")]
@@ -159,6 +160,7 @@ namespace SharpGLTF.Scenes
             // save the model as GLB
 
             scene.AttachToCurrentTest("shapes.glb");
+            scene.AttachToCurrentTest("shapes.plotly");
         }
 
         [Test]
@@ -477,7 +479,7 @@ namespace SharpGLTF.Scenes
                 .FirstOrDefault(item => item.Contains(path));
 
             var srcModel = Schema2.ModelRoot.Load(path, Validation.ValidationMode.TryFix);
-            Assert.NotNull(srcModel);
+            Assert.NotNull(srcModel);            
 
             // perform roundtrip
 
@@ -512,6 +514,9 @@ namespace SharpGLTF.Scenes
             // save file
 
             path = System.IO.Path.GetFileNameWithoutExtension(path);
+
+            srcModel.AttachToCurrentTest(path + "_src" + ".plotly");
+
             srcModel.AttachToCurrentTest(path + "_src" + ".glb");
             rowModel.AttachToCurrentTest(path + "_row" + ".glb");
             colModel.AttachToCurrentTest(path + "_col" + ".glb");
@@ -672,7 +677,6 @@ namespace SharpGLTF.Scenes
             scene.AddScene(polly, xform1);
 
             scene.AttachToCurrentTest("construction.glb");
-
         }
 
     }