public void NormalsFromEmptyArray()
        {
            var ps = new V3f[0];
            var kd = ps.BuildKdTree();
            var ns = ps.EstimateNormalsAsync(16, kd).Result;

            Assert.IsTrue(ns.Length == 0);
        }
        public void CanEstimateNormals_FromZeroToThreePoints()
        {
            var r = new Random();

            for (var n = 0; n < 4; n++)
            {
                var ps = new V3f[n].SetByIndex(_ => new V3f(r.NextDouble(), r.NextDouble(), r.NextDouble()));

                var kd = ps.BuildKdTree();

                var ns = Normals.EstimateNormals(ps, 16, kd);
                Assert.IsTrue(ns.Length == n);
            }
        }
        public void CreatingKdTreeDoesNotChangeOrderOfPoints()
        {
            var r    = new Random();
            var ps   = new V3f[1000].SetByIndex(_ => new V3f(r.NextDouble(), r.NextDouble(), r.NextDouble()));
            var copy = ps.Copy();

            var kd = ps.BuildKdTree();

            Assert.IsTrue(kd != null);
            Assert.IsTrue(ps.Length == copy.Length);
            for (var i = 0; i < ps.Length; i++)
            {
                Assert.IsTrue(ps[i] == copy[i]);
            }
        }
Exemple #4
0
        /// <summary>
        /// </summary>
        private static PointSetNode GenerateLod(this PointSetNode self, long octreeSplitLimit, Action callback, CancellationToken ct)
        {
            if (self == null)
            {
                throw new ArgumentNullException(nameof(self));
            }

            ct.ThrowIfCancellationRequested();

            callback?.Invoke();

            if (self.IsLeaf)
            {
                return(self.WithLod());
            }

            if (self.Subnodes == null || self.Subnodes.Length != 8)
            {
                throw new InvalidOperationException();
            }

            var subcells           = self.Subnodes.Map(x => x?.Value.GenerateLod(octreeSplitLimit, callback, ct));
            var subcellsTotalCount = (long)subcells.Sum(x => x?.PointCountTree);

            var needsCs = subcells.Any(x => x != null ? (x.HasColors || x.HasLodColors) : false);
            var needsNs = subcells.Any(x => x != null ? (x.HasNormals || x.HasLodNormals) : false);
            var needsIs = subcells.Any(x => x != null ? (x.HasIntensities || x.HasLodIntensities) : false);

            var fractions = new double[8].SetByIndex(
                ci => subcells[ci] != null ? (subcells[ci].PointCountTree / (double)subcellsTotalCount) : 0.0
                );
            var remainder = 0.1;
            var counts    = fractions.Map(x =>
            {
                var fn    = octreeSplitLimit * x + remainder;
                var n     = (int)fn;
                remainder = fn - n;
                return(n);
            });
            var e = octreeSplitLimit - counts.Sum();

            if (e != 0)
            {
                throw new InvalidOperationException();
            }

            // generate LoD data ...
            var lodPs = new V3f[octreeSplitLimit];
            var lodCs = needsCs ? new C4b[octreeSplitLimit] : null;
            var lodNs = needsNs ? new V3f[octreeSplitLimit] : null;
            var lodIs = needsIs ? new int[octreeSplitLimit] : null;
            var i     = 0;

            for (var ci = 0; ci < 8; ci++)
            {
                if (counts[ci] == 0)
                {
                    continue;
                }
                var subcell = subcells[ci];
                if (subcell == null)
                {
                    continue;
                }

                var subps = subcell.IsLeaf ? subcell.Positions.Value : subcell.LodPositions.Value;
                var subcs = needsCs ? (subcell.IsLeaf ? subcell.Colors.Value : subcell.LodColors.Value) : null;
                var subns = needsNs ? (subcell.IsLeaf ? subcell.Normals.Value : subcell.LodNormals.Value) : null;
                var subis = needsIs ? (subcell.IsLeaf ? subcell.Intensities.Value : subcell.LodIntensities.Value) : null;

                var jmax = subps.Length;
                var dj   = (jmax + 0.49) / counts[ci];
                var oldI = i;
                for (var j = 0.0; j < jmax; j += dj)
                {
                    var jj = (int)j;
                    lodPs[i] = (V3f)(((V3d)subps[jj] + subcell.Center) - self.Center);
                    if (needsCs)
                    {
                        lodCs[i] = subcs[jj];
                    }
                    if (needsNs)
                    {
                        lodNs[i] = subns[jj];
                    }
                    if (needsIs)
                    {
                        lodIs[i] = subis[jj];
                    }
                    i++;
                }
            }
            var lodKd = lodPs.BuildKdTree();

            // store LoD data ...
            var lodPsId = Guid.NewGuid();

            self.Storage.Add(lodPsId, lodPs, ct);

            var lodKdId = Guid.NewGuid();

            self.Storage.Add(lodKdId, lodKd.Data, ct);

            var lodCsId = needsCs ? (Guid?)Guid.NewGuid() : null;

            if (needsCs)
            {
                self.Storage.Add(lodCsId.Value, lodCs, ct);
            }

            var lodNsId = needsNs ? (Guid?)Guid.NewGuid() : null;

            if (needsNs)
            {
                self.Storage.Add(lodNsId.Value, lodNs, ct);
            }

            var lodIsId = needsIs ? (Guid?)Guid.NewGuid() : null;

            if (needsIs)
            {
                self.Storage.Add(lodIsId.Value, lodIs, ct);
            }

            var result = self.WithLod(lodPsId, lodCsId, lodNsId, lodIsId, lodKdId, subcells);

            return(result);
        }