コード例 #1
0
        public void HasBoundingBoxExact()
        {
            var storage = PointSetTests.CreateStorage();

            var ps = new[]
            {
                new V3d(0.1, 0.1, 0.1),
                new V3d(0.9, 0.1, 0.1),
                new V3d(0.9, 0.9, 0.1),
                new V3d(0.1, 0.9, 0.1),
                new V3d(0.1, 0.1, 0.9),
                new V3d(0.9, 0.1, 0.9),
                new V3d(0.9, 0.9, 0.9),
                new V3d(0.1, 0.9, 0.9),
            };

            var config = ImportConfig.Default.WithStorage(storage).WithRandomKey();
            var n      = PointCloud.Chunks(new Chunk(ps, null), config).Root.Value;

            Assert.IsTrue(n.HasBoundingBoxExactLocal);
            Assert.IsTrue(n.BoundingBoxExactLocal == new Box3f(new V3f(-0.4f), new V3f(0.4f)));

            Assert.IsTrue(n.HasBoundingBoxExactGlobal);
            Assert.IsTrue(n.BoundingBoxExactGlobal.Min.ApproxEqual(new V3d(0.1), 1e-6));
            Assert.IsTrue(n.BoundingBoxExactGlobal.Max.ApproxEqual(new V3d(0.9), 1e-6));
        }
コード例 #2
0
        public void CanImportChunk_Reproject()
        {
            int n  = 10;
            var ps = new V3d[n];

            for (var i = 0; i < n; i++)
            {
                ps[i] = new V3d(i, 0, 0);
            }
            var bb = new Box3d(ps);

            var chunk = new Chunk(ps);

            Assert.IsTrue(chunk.Count == 10);
            Assert.IsTrue(chunk.BoundingBox == bb);

            var config = ImportConfig.Default
                         .WithStorage(PointCloud.CreateInMemoryStore())
                         .WithKey("test")
                         .WithOctreeSplitLimit(10)
                         .WithReproject(xs => xs.Select(x => x += V3d.OIO).ToArray())
            ;
            var pointcloud = PointCloud.Chunks(chunk, config);

            Assert.IsTrue(pointcloud.BoundingBox == bb + V3d.OIO);
        }
コード例 #3
0
        public void CanImport_WithoutKey()
        {
            int n  = 10;
            var ps = new V3d[n];

            for (var i = 0; i < n; i++)
            {
                ps[i] = new V3d(i, 0, 0);
            }

            var chunk = new Chunk(ps);

            Assert.IsTrue(chunk.Count == 10);

            var config = ImportConfig.Default
                         .WithStorage(PointCloud.CreateInMemoryStore())
                         .WithKey(null)
                         .WithOctreeSplitLimit(10)
                         .WithCreateOctreeLod(false)
                         .WithDeduplicateChunks(false)
                         .WithMinDist(0.0)
                         .WithReproject(null)
                         .WithEstimateNormals(null)
            ;
            var pointcloud = PointCloud.Chunks(chunk, config);

            Assert.IsTrue(pointcloud.Id != null);
        }
コード例 #4
0
        public void HasPointDistance()
        {
            var storage = PointSetTests.CreateStorage();

            var ps = new[]
            {
                new V3d(0.1, 0.1, 0.1),
                new V3d(0.9, 0.1, 0.1),
                new V3d(0.9, 0.9, 0.1),
                new V3d(0.1, 0.9, 0.1),
                new V3d(0.1, 0.1, 0.9),
                new V3d(0.9, 0.1, 0.9),
                new V3d(0.9, 0.9, 0.9),
                new V3d(0.1, 0.9, 0.9),
            };

            var config = ImportConfig.Default.WithStorage(storage).WithRandomKey();
            var n      = PointCloud.Chunks(new Chunk(ps, null), config).Root.Value;

            Assert.IsTrue(n.HasPointDistanceAverage);
            Assert.IsTrue(n.HasPointDistanceStandardDeviation);

            Assert.IsTrue(n.PointDistanceAverage.ApproximateEquals(0.8f, 1e-5f));
            Assert.IsTrue(n.PointDistanceStandardDeviation.ApproximateEquals(0.0f, 1e-5f));
        }
コード例 #5
0
        public void NoLod()
        {
            var chunk = new Chunk(new[]
            {
                new V3d(0, 0, 0),
                new V3d(1, 0, 0),
                new V3d(1, 1, 0),
                new V3d(0, 1, 0)
            });

            var config = ImportConfig.Default
                         .WithInMemoryStore()
                         .WithRandomKey()
                         .WithCreateOctreeLod(false)
            ;
            var cloud = PointCloud.Chunks(chunk, config);

            Assert.IsTrue(cloud.HasNormals == false);
            Assert.IsTrue(cloud.HasLodNormals == false);

            config = config
                     .WithRandomKey()
                     .WithEstimateNormals(ps => Normals.EstimateNormals((V3d[])ps, 5))
            ;
            var cloud2 = cloud.GenerateNormals(config);

            Assert.IsTrue(cloud2.HasNormals == true);
            Assert.IsTrue(cloud2.Root.Value.Normals.Value.All(n => n == V3f.OOI));
            Assert.IsTrue(cloud2.HasLodNormals == false);
        }
コード例 #6
0
        public void HasCentroid()
        {
            var storage = PointSetTests.CreateStorage();

            var ps = new[]
            {
                new V3d(0.1, 0.1, 0.1),
                new V3d(0.9, 0.1, 0.1),
                new V3d(0.9, 0.9, 0.1),
                new V3d(0.1, 0.9, 0.1),
                new V3d(0.1, 0.1, 0.9),
                new V3d(0.9, 0.1, 0.9),
                new V3d(0.9, 0.9, 0.9),
                new V3d(0.1, 0.9, 0.9),
            };

            var config = ImportConfig.Default.WithStorage(storage).WithRandomKey();
            var n      = PointCloud.Chunks(new Chunk(ps, null), config).Root.Value;

            Assert.IsTrue(n.HasCentroidLocal);
            Assert.IsTrue(n.HasCentroidLocalStdDev);

            Assert.IsTrue(n.CentroidLocal.ApproxEqual(V3f.Zero, 1e-5f));
            Assert.IsTrue(n.CentroidLocalStdDev.ApproximateEquals(0.0f, 1e-5f));
        }
コード例 #7
0
        public void HasTreeDepth2()
        {
            var r       = new Random();
            var storage = PointSetTests.CreateStorage();

            var ps = new V3d[20000].SetByIndex(_ => new V3d(r.NextDouble(), r.NextDouble(), r.NextDouble()));

            var config = ImportConfig.Default.WithStorage(storage).WithRandomKey();
            var n      = PointCloud.Chunks(new Chunk(ps, null), config).Root.Value;

            Assert.IsTrue(n.HasMinTreeDepth);
            Assert.IsTrue(n.HasMaxTreeDepth);

            Assert.IsTrue(n.MinTreeDepth == 1);
            Assert.IsTrue(n.MaxTreeDepth == 1);
        }
コード例 #8
0
        private static PointSet CreateRandomPointsInUnitCube(int n, int splitLimit)
        {
            var r  = new Random();
            var ps = new V3d[n];

            for (var i = 0; i < n; i++)
            {
                ps[i] = new V3d(r.NextDouble(), r.NextDouble(), r.NextDouble());
            }
            var config = ImportConfig.Default
                         .WithStorage(PointCloud.CreateInMemoryStore())
                         .WithKey("test")
                         .WithOctreeSplitLimit(splitLimit)
            ;

            return(PointCloud.Chunks(new Chunk(ps, null), config));
        }
コード例 #9
0
        internal static void TestKNearest()
        {
            var sw   = new Stopwatch();
            var rand = new Random();

            Report.BeginTimed("generating point clouds");
            var cloud0 = CreateRandomPointsInUnitCube(1000000, 8192);
            var cloud1 = CreateRandomPointsInUnitCube(1000000, 8192);

            Report.EndTimed();

            var ps0 = cloud0.QueryAllPoints().SelectMany(chunk => chunk.Positions).ToArray();

            sw.Restart();
            for (var i = 0; i < ps0.Length; i++)
            {
                var p = cloud1.QueryPointsNearPoint(ps0[i], 0.1, 1);
                if (i % 100000 == 0)
                {
                    Console.WriteLine($"{i,20:N0}     {sw.Elapsed}");
                }
            }
            sw.Stop();
            Console.WriteLine($"{ps0.Length,20:N0}     {sw.Elapsed}");

            PointSet CreateRandomPointsInUnitCube(int n, int splitLimit)
            {
                var r  = new Random();
                var ps = new V3d[n];

                for (var i = 0; i < n; i++)
                {
                    ps[i] = new V3d(r.NextDouble(), r.NextDouble(), r.NextDouble());
                }
                var config = ImportConfig.Default
                             .WithStorage(PointCloud.CreateInMemoryStore(new LruDictionary <string, object>(1024 * 1024 * 1024)))
                             .WithKey("test")
                             .WithOctreeSplitLimit(splitLimit)
                ;

                return(PointCloud.Chunks(new Chunk(ps, null), config));
            }
        }
コード例 #10
0
        public void CanImport_DuplicateKey()
        {
            int n  = 10;
            var ps = new V3d[n];

            for (var i = 0; i < n; i++)
            {
                ps[i] = new V3d(i, 0, 0);
            }

            var chunk = new Chunk(ps);

            Assert.IsTrue(chunk.Count == 10);

            var config = ImportConfig.Default
                         .WithStorage(PointCloud.CreateInMemoryStore())
                         .WithKey("test")
                         .WithOctreeSplitLimit(10)
                         .WithCreateOctreeLod(false)
                         .WithDeduplicateChunks(false)
                         .WithMinDist(0.0)
                         .WithReproject(null)
                         .WithEstimateNormals(null)
            ;


            var pointcloud = PointCloud.Chunks(new Chunk[] { }, config);

            Assert.IsTrue(pointcloud.Id != null);
            Assert.IsTrue(pointcloud.PointCount == 0);


            var pointcloud2 = PointCloud.Chunks(chunk, config);

            Assert.IsTrue(pointcloud2.Id != null);
            Assert.IsTrue(pointcloud2.PointCount == 10);


            var reloaded = config.Storage.GetPointSet("test", CancellationToken.None);

            Assert.IsTrue(reloaded.PointCount == 10);
        }
コード例 #11
0
        public void CanParsePtsChunksThenImportThenLoadFromStore()
        {
            var filename = Path.Combine(Config.TestDataDir, "test.pts");

            if (!File.Exists(filename))
            {
                Assert.Ignore($"File not found: {filename}");
            }
            TestContext.WriteLine($"testfile is '{filename}'");
            var config = ImportConfig.Default
                         .WithStorage(PointCloud.CreateInMemoryStore())
                         .WithKey("test")
            ;
            var ptsChunks = Data.Points.Import.Pts.Chunks(filename, config);
            var pointset  = PointCloud.Chunks(ptsChunks, config);

            Assert.IsTrue(pointset.Id == "test");
            var pointset2 = config.Storage.GetPointSet("test", CancellationToken.None);

            Assert.IsTrue(pointset2 != null);
            Assert.IsTrue(pointset2.PointCount == 3);
        }
コード例 #12
0
        public void CanImportChunk_EstimateNormals()
        {
            int n  = 10;
            var ps = new V3d[n];

            for (var i = 0; i < n; i++)
            {
                ps[i] = new V3d(i, 0, 0);
            }

            var chunk = new Chunk(ps);

            Assert.IsTrue(chunk.Count == 10);

            var config = ImportConfig.Default
                         .WithStorage(PointCloud.CreateInMemoryStore())
                         .WithKey("test")
                         .WithOctreeSplitLimit(10)
            ;
            var pointcloud = PointCloud.Chunks(chunk, config);
            var node       = pointcloud.Root.Value;

            Assert.IsTrue(node.IsLeaf);
            Assert.IsTrue(node.HasNormals == false);


            config = ImportConfig.Default
                     .WithStorage(PointCloud.CreateInMemoryStore())
                     .WithKey("test")
                     .WithOctreeSplitLimit(10)
                     .WithEstimateNormals(xs => xs.Select(x => V3f.OOI).ToArray())
            ;
            pointcloud = PointCloud.Chunks(chunk, config);
            node       = pointcloud.Root.Value;
            Assert.IsTrue(node.IsLeaf);
            Assert.IsTrue(node.HasNormals == true);
            Assert.IsTrue(node.Normals.Value.All(x => x == V3f.OOI));
        }
コード例 #13
0
        internal static void PerfTestJuly2019()
        {
            var filename = @"T:\Vgm\Data\2017-10-20_09-44-27_1mm_shade_norm_5pp - Cloud.pts";
            //var filename = @"T:\Vgm\Data\JBs_Haus.pts";

            var config = ImportConfig.Default
                         .WithInMemoryStore()
                         .WithRandomKey()
                         .WithVerbose(true)
                         .WithMaxDegreeOfParallelism(0)
                         .WithMinDist(0.01)
                         .WithNormalizePointDensityGlobal(true)
            ;

            Report.BeginTimed("total");

            var chunks = Pts.Chunks(filename, config.ParseConfig);
            var pc     = PointCloud.Chunks(chunks, config);

            Report.EndTimed();

            Report.Line($"count -> {pc.PointCount}");
        }
コード例 #14
0
        private static PointSet CreateRegularPointsInUnitCube(int n, int splitLimit)
        {
            var ps    = new List <V3d>();
            var step  = 1.0 / n;
            var start = step * 0.5;

            for (var x = start; x < 1.0; x += step)
            {
                for (var y = start; y < 1.0; y += step)
                {
                    for (var z = start; z < 1.0; z += step)
                    {
                        ps.Add(new V3d(x, y, z));
                    }
                }
            }
            var config = ImportConfig.Default
                         .WithStorage(PointCloud.CreateInMemoryStore())
                         .WithKey("test")
                         .WithOctreeSplitLimit(splitLimit)
            ;

            return(PointCloud.Chunks(new Chunk(ps, null), config));
        }
コード例 #15
0
        public void CanImport_Empty()
        {
            var config = ImportConfig.Default
                         .WithStorage(PointCloud.CreateInMemoryStore())
                         .WithKey("test")
                         .WithOctreeSplitLimit(10)
                         .WithCreateOctreeLod(false)
                         .WithDeduplicateChunks(false)
                         .WithMinDist(0.0)
                         .WithReproject(null)
                         .WithEstimateNormals(null)
            ;


            var pointcloud = PointCloud.Chunks(new Chunk[] { }, config);

            Assert.IsTrue(pointcloud.Id == "test");
            Assert.IsTrue(pointcloud.PointCount == 0);

            var reloaded = config.Storage.GetPointSet("test", CancellationToken.None);

            Assert.IsTrue(reloaded.Id == "test");
            Assert.IsTrue(reloaded.PointCount == 0);
        }
コード例 #16
0
        public void CanImportChunk_MinDist()
        {
            int n  = 100;
            var r  = new Random();
            var ps = new V3d[n];

            for (var i = 0; i < n; i++)
            {
                ps[i] = new V3d(r.NextDouble(), r.NextDouble(), r.NextDouble());
            }
            var chunk = new Chunk(ps);

            Assert.IsTrue(chunk.Count == 100);

            var config = ImportConfig.Default
                         .WithStorage(PointCloud.CreateInMemoryStore())
                         .WithKey("test")
                         .WithOctreeSplitLimit(10)
                         .WithMinDist(0.5)
            ;
            var pointcloud = PointCloud.Chunks(chunk, config);

            Assert.IsTrue(pointcloud.PointCount < 100);
        }
コード例 #17
0
        public void ProgressCallbackWorks()
        {
            var CHUNKSIZE  = 10000;
            var CHUNKCOUNT = 10;

            var countProgressCallbacks = 0L;

            var config = ImportConfig.Default
                         .WithStorage(PointCloud.CreateInMemoryStore())
                         .WithKey("test")
                         .WithProgressCallback(x => Interlocked.Increment(ref countProgressCallbacks));

            ;

            var pointcloud = PointCloud.Chunks(GenerateChunks(CHUNKSIZE).Take(CHUNKCOUNT), config);

            Assert.IsTrue(pointcloud.PointCount == CHUNKSIZE * CHUNKCOUNT);

            Assert.IsTrue(countProgressCallbacks > 10);


            IEnumerable <Chunk> GenerateChunks(int numberOfPointsPerChunk)
            {
                var r = new Random();

                while (true)
                {
                    var _ps = new V3d[numberOfPointsPerChunk];
                    for (var i = 0; i < numberOfPointsPerChunk; i++)
                    {
                        _ps[i] = new V3d(r.NextDouble(), r.NextDouble(), r.NextDouble());
                    }
                    yield return(new Chunk(_ps));
                }
            }
        }
コード例 #18
0
        internal static void TestE57()
        {
            var sw = new Stopwatch();

            CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture;
            var filename        = @"T:\Vgm\Data\E57\Innenscan_FARO.e57";
            var fileSizeInBytes = new FileInfo(filename).Length;

            var info = E57.E57Info(filename, ParseConfig.Default);

            Report.Line($"total bounds: {info.Bounds}");
            Report.Line($"total count : {info.PointCount:N0}");

            var config = ImportConfig.Default
                         .WithInMemoryStore()
                         .WithRandomKey()
                         .WithVerbose(true)
                         .WithMaxDegreeOfParallelism(0)
                         .WithMinDist(0.01)
            ;

            Report.BeginTimed("total");

            var chunks = E57
                         .Chunks(filename, config.ParseConfig)
                         //.Take(10)
                         //.AsParallel()
                         //.Select(x => x.ImmutableFilterMinDistByCell(new Cell(x.BoundingBox), config))
                         //.Select(x => x.ImmutableFilterSequentialMinDistL1(0.01))
                         //.ToArray()
            ;
            var pc = PointCloud.Chunks(chunks, config);

            Report.EndTimed();

            //var memstore = new SimpleMemoryStore().ToPointCloudStore();

            // classic
            //var foo = chunks.AsParallel().Select(x => InMemoryPointSet.Build(x, 8192).ToPointSetCell(memstore));
            //var r = foo.MapReduceParallel((first, second, ct2) =>
            //{
            //    var merged = first.Merge(second, 8192, null, default);
            //    memstore.Add(Guid.NewGuid().ToString(), merged, default);
            //    Report.Line($"{first.PointCountTree,12:N0} + {second.PointCountTree,12:N0} -> {merged.PointCountTree,12:N0}");
            //    return merged;
            //}, 0);

            //// test 1
            //Report.BeginTimed("merging all chunks");
            //var chunk = Chunk.Empty;
            //foreach (var x in chunks) chunk = Chunk.ImmutableMerge(chunk, x);
            //Report.Line($"points     : {chunk.Count:N0}");
            //Report.EndTimed();

            //Report.BeginTimed("filter mindist");
            //chunk = chunk.ImmutableFilterMinDistByCell(0.01, new Cell(chunk.BoundingBox));
            //Report.Line($"points     : {chunk.Count:N0}");
            //Report.EndTimed();

            //Report.BeginTimed("slots");
            //var slots = chunk.Positions.GroupBy(p => (V3i)p).ToArray();
            //Report.Line($"[slots] {slots.Length}");
            //var slotsCountAvg = slots.Sum(x => x.Count() / (double)slots.Length);
            //var slotsCountMin = slots.Min(x => x.Count());
            //var slotsCountMax = slots.Max(x => x.Count());
            //var slotsCountSd = (slots.Sum(x => (x.Count() - slotsCountAvg).Square()) / slots.Length).Sqrt();
            //Report.Line($"[slots] count avg = {slotsCountAvg}");
            //Report.Line($"[slots] count min = {slotsCountMin}");
            //Report.Line($"[slots] count max = {slotsCountMax}");
            //Report.Line($"[slots] count sd  = {slotsCountSd}");
            //Report.EndTimed();


            //Report.BeginTimed("build octree");
            //var octree = InMemoryPointSet.Build(chunk, 8192);
            //Report.EndTimed();

            //Report.BeginTimed("toPointSetCell");
            //var psc = octree.ToPointSetCell(memstore);
            //var ps = new PointSet(memstore, "foo", psc.Id, 8192);
            //Report.EndTimed();

            //Report.BeginTimed("generate lod");
            //var psWithNormals = ps.GenerateLod(config);
            //Report.EndTimed();



            //Report.Line($"chunks: {foo.Count}");



            //return;

            //var lastProgress = 0.0;
            //config = ImportConfig.Default
            //    .WithInMemoryStore()
            //    .WithRandomKey()
            //    .WithVerbose(false)
            //    .WithMaxDegreeOfParallelism(0)
            //    .WithMinDist(0.01)
            //    .WithProgressCallback(x =>
            //    {
            //        if (x < lastProgress) Console.WriteLine("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH"); else lastProgress = x;
            //        Console.WriteLine($"[PROGRESS]; {x,8:0.00000}; {sw.Elapsed.TotalSeconds:0.00}");
            //    })
            //    ;

            //chunks = E57.Chunks(filename, config.ParseConfig);
            //var pointcloud = PointCloud.Chunks(chunks, config);
            //Console.WriteLine($"pointcloud.PointCount  : {pointcloud.PointCount}");
            //Console.WriteLine($"pointcloud.Bounds      : {pointcloud.Bounds}");
            //Console.WriteLine($"pointcloud.BoundingBox : {pointcloud.BoundingBox}");

            //var chunks = E57.Chunks(filename, config);
            //var pointcloud = PointCloud.Chunks(chunks, config);
            //Console.WriteLine($"pointcloud.PointCount  : {pointcloud.PointCount}");
            //Console.WriteLine($"pointcloud.Bounds      : {pointcloud.Bounds}");
            //Console.WriteLine($"pointcloud.BoundingBox : {pointcloud.BoundingBox}");


            //var leafLodPointCount = 0L;
            //pointcloud.Root.Value.ForEachNode(true, n => { if (n.IsLeaf) leafLodPointCount += n.LodPositionsAbsolute.Length; });
            //Console.WriteLine($"leaf lod point count :{leafLodPointCount}");

            //foreach (var chunk in chunks)
            //{
            //    for (var i = 0; i < chunk.Count; i++)
            //    {
            //        Console.WriteLine($"{chunk.Positions[i]:0.000} {chunk.Colors?[i]}");
            //    }
            //}

            //Console.WriteLine($"chunks point count: {chunks.Sum(x => x.Positions.Count)}");
            //Console.WriteLine($"chunks bounds     : {new Box3d(chunks.SelectMany(x => x.Positions))}");

            //using (var w = File.CreateText("test.txt"))
            //{
            //    foreach (var chunk in chunks)
            //    {
            //        for (var i = 0; i < chunk.Count; i++)
            //        {
            //            var p = chunk.Positions[i];
            //            var c = chunk.Colors[i];
            //            w.WriteLine($"{p.X} {p.Y} {p.Z} {c.R} {c.G} {c.B}");
            //        }
            //    }
            //}
            //return;

            /*
             * var stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
             * ASTM_E57.VerifyChecksums(stream, fileSizeInBytes);
             * var header = ASTM_E57.E57FileHeader.Parse(stream);
             *
             * //Report.BeginTimed("parsing E57 file");
             * //var take = int.MaxValue;
             * //var data = header.E57Root.Data3D.SelectMany(x => x.StreamCartesianCoordinates(false)).Take(take).Chunk(1000000).ToList();
             * //Report.EndTimed();
             * //Report.Line($"#points: {data.Sum(xs => xs.Length)}");
             *
             * foreach (var p in header.E57Root.Data3D.SelectMany(x => x.StreamPoints(false))) Console.WriteLine(p.Item1);
             *
             * //var ps = PointCloud.Parse(filename, ImportConfig.Default)
             * //    .SelectMany(x => x.Positions)
             * //    .ToArray()
             * //    ;
             */
        }
コード例 #19
0
        internal static void TestE57()
        {
            CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture;
            var filename        = @"test.e57";
            var fileSizeInBytes = new FileInfo(filename).Length;

            var config = ImportConfig.Default
                         .WithInMemoryStore()
                         .WithRandomKey()
                         .WithVerbose(true)
                         .WithMaxDegreeOfParallelism(0)
                         .WithMinDist(0.005)
            ;

            var chunks     = E57.Chunks(filename, config).ToList();
            var pointcloud = PointCloud.Chunks(chunks, config);

            Console.WriteLine($"pointcloud.PointCount  : {pointcloud.PointCount}");
            Console.WriteLine($"pointcloud.Bounds      :{pointcloud.Bounds}");
            Console.WriteLine($"pointcloud.BoundingBox :{pointcloud.BoundingBox}");

            var leafLodPointCount = 0L;

            pointcloud.Root.Value.ForEachNode(true, n => { if (n.IsLeaf)
                                                           {
                                                               leafLodPointCount += n.LodPositionsAbsolute.Length;
                                                           }
                                              });
            Console.WriteLine($"leaf lod point count :{leafLodPointCount}");

            //foreach (var chunk in chunks)
            //{
            //    for (var i = 0; i < chunk.Count; i++)
            //    {
            //        Console.WriteLine($"{chunk.Positions[i]:0.000} {chunk.Colors?[i]}");
            //    }
            //}

            Console.WriteLine($"chunks point count: {chunks.Sum(x => x.Positions.Count)}");
            Console.WriteLine($"chunks bounds     : {new Box3d(chunks.SelectMany(x => x.Positions))}");

            //using (var w = File.CreateText("test.txt"))
            //{
            //    foreach (var chunk in chunks)
            //    {
            //        for (var i = 0; i < chunk.Count; i++)
            //        {
            //            var p = chunk.Positions[i];
            //            var c = chunk.Colors[i];
            //            w.WriteLine($"{p.X} {p.Y} {p.Z} {c.R} {c.G} {c.B}");
            //        }
            //    }
            //}
            //return;

            /*
             * var stream = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
             * ASTM_E57.VerifyChecksums(stream, fileSizeInBytes);
             * var header = ASTM_E57.E57FileHeader.Parse(stream);
             *
             * //Report.BeginTimed("parsing E57 file");
             * //var take = int.MaxValue;
             * //var data = header.E57Root.Data3D.SelectMany(x => x.StreamCartesianCoordinates(false)).Take(take).Chunk(1000000).ToList();
             * //Report.EndTimed();
             * //Report.Line($"#points: {data.Sum(xs => xs.Length)}");
             *
             * foreach (var p in header.E57Root.Data3D.SelectMany(x => x.StreamPoints(false))) Console.WriteLine(p.Item1);
             *
             * //var ps = PointCloud.Parse(filename, ImportConfig.Default)
             * //    .SelectMany(x => x.Positions)
             * //    .ToArray()
             * //    ;
             */
        }